4

I have read Convert from rectangular coordinates to polar coordinates but didn't find a solution for me.

I have defined a pic named compass which I plan to use several times in different scaled version (and with rotated with an different angle).

I was able to define a second pic named yacht, which is relocatable, scalable and rotatable. The only difference is, that I used polar coordinates, to construct the compass rose.

Here is an example document of the intended usage:

\begin{tikzpicture}
  \node (a) {A} ;
  \path pic (b) at ([xshift=5cm] a) {yacht} ;
  \pic [below=2cm of a, scale=.4, rotate=220] (c) {yacht} ;
  \pic [scale=.2, rotate=120, right=2cm of c-yacht] (d) {yacht} ;
  \pic [below=8cm of d-yacht, scale=.2, rotate=60] (error) {compass} ;
  \pic [right=9cm of error-compass ] (error) {compass} ;
\end{tikzpicture}

(For comparison, the first call of the yacht is unscaled and not rotated.)

This is the result.

Example of the non scaling compass rose

What went wrong?

Here is the complete MWE (I removed the definition of the yachtto keep it small).

\documentclass[12pt]{article}
\usepackage[ngerman]{babel}
\usepackage[T1]{fontenc}
\usepackage{tikz}

%% Lade weitere Pakete
\usetikzlibrary{
  positioning}



\def\needle{50}
\def\short{\needle/10}
\newcommand{\needlelength}[1]{\def\needle{#1}}

\tikzset{
  rose/.style = {
    % xscale      = 1/2,
    % yscale      = 1/2,
    % scale       = 0.2,
    font        =\large,
    semithick,
  },
  leftrose/.style = {
    rose,
    fill = black!70,
  },
  rightrose/.style = {
    fill = black!10,
  },
}

\tikzset{
  pics/compassneedle/.style 2 args={
    code={
      %% Try to draw a needle by aims of polar coordinates.
      \filldraw[leftrose]
      % start at origin, 
      (0:0)
      % move nw for the short distance
      -- ({#1+45}:{\short*\needle})
      % reach the tip at north
      -- ({#1}:{\needle})
      % go back to origin
      -- cycle ;
      % repeat the same on the eastern side.
      \filldraw[rightrose]
      % start at origin, 
      (0:0)
      % move ne for the short distance
      -- ({#1-45}:{\short*\needle})
      % reach the tip at north
      -- ({#1}:{\needle})
      % go back to origin
      -- cycle ;
      %%
      %% Insert the direction
      \node[rotate={#1-90}] at ({#1}:{1.1*\needle}) {#2} ;
    }
  }, % end of compassneedle
}

\tikzset{%
  pics/compass/.style={
    code={
      %% Position a named node here
      \node (-compass) {};

      %% Begin with a layer of the rose pointing to ne, nw, sw, se.
      %% This layer shall be somewhat shorter than the main layer.
      \needlelength{3.5}
      \foreach \angle/\name in {45/NE, 135/NW, 225/SW, 315/SE} {
        \pic{compassneedle={\angle}{\name}} ;
      }
      %% Next, put a second layer with the main directions.  Don't
      %% forget to increase the needle lengths accordingly.
      \needlelength{4}
      \foreach  \angle/\name in {0/E, 90/N, 180/W, 270/S} {
        \pic{compassneedle={\angle}{\name}} ;
      }
    }
  },
}
\makeatletter

\begin{document}

\begin{tikzpicture}
  \pic [scale=.2] (error) {compass} ;
  \pic [right=9cm of error-compass ] (error) {compass} ;
\end{tikzpicture}


\end{document}% 
2
  • 3
    This is normal because scale in some scope only scale the coordinates and not the nodes, pics, fonts, line width, .... You have different choices : use transform canvas={scale=...}, or pass the scale as parameter to the compass, and then apply it to the sub-pics, or simply do not use sub-pics.
    – Kpym
    Commented Apr 3, 2018 at 14:37
  • 1
    @Kpym thanks for the insight. Not using pics is (right now) the least desirable option for me. I'll give the transform canvas={scale=} a try.
    – Jan
    Commented Apr 3, 2018 at 15:39

3 Answers 3

7

Here is a (golf type) example of \pic{compass} that can be scaled and styled.

\documentclass[tikz,border=7pt]{standalone}
\tikzset{
  compass/.pic = {
    \foreach[count=\i,evaluate={\m=div(\i-1,4);\a=90*\i-45*(\m+1)}] \d in {NE,NW,SW,SE,E,N,W,S}{
      \filldraw[pic actions,rotate=\a,scale=.7+.3*\m] (0,0) -- (45:1)--(0:3) node[transform shape,rotate=-90,above]{\d};
      \filldraw[pic actions,fill=white,rotate=\a,scale=.7+.3*\m] (0,0) -- (-45:1)--(0:3)--cycle;
    };
  }
}
\begin{document}
  \begin{tikzpicture}
    \pic{compass};
    \pic[scale=.7,fill=red,text=blue] at (7,0) {compass};
  \end{tikzpicture}
\end{document}

enter image description here

3
  • Wow :-), that is really impressive!
    – Jan
    Commented Apr 4, 2018 at 5:35
  • 'Golf type'? Like a golf ball? Confused .... (+1 for the rest - just I don't get the description.)
    – cfr
    Commented Apr 4, 2018 at 14:47
  • @cfr like code colf(ing).
    – Kpym
    Commented Apr 4, 2018 at 15:54
2

As suggested by @Kpym in his comment, one can use the option transform canvas={scale=...}.

So instead of

\begin{tikzpicture}
  \pic [scale=.2] (error) {compass} ;
  \pic [right=9cm of error-compass ] (full-size) {compass} ;
\end{tikzpicture}

you should use

\begin{tikzpicture}
  \pic [transform canvas={scale=.2}] (error) {compass} ;
  \pic [right=9cm of error-compass ] (full-size) {compass} ;
\end{tikzpicture}

This has worked for me, but it placed the pic in the middle of my picture. So you have to add some correcting movements in x and y also!

1
  • 4
    Instead of transform canvas, here \pic [scale=.2, transform shape] (error) {compass} ; would be the way to go for nodes to pick up the transformations
    – percusse
    Commented Apr 3, 2018 at 16:12
1

You can also use \resizebox{width}{height}{what you want to resize}

\documentclass[12pt]{article}
\usepackage[ngerman]{babel}
\usepackage[T1]{fontenc}
\usepackage{tikz}

%% Lade weitere Pakete
\usetikzlibrary{
  positioning}



\def\needle{50}
\def\short{\needle/10}
\newcommand{\needlelength}[1]{\def\needle{#1}}

\tikzset{
  rose/.style = {
    % xscale      = 1/2,
    % yscale      = 1/2,
    % scale       = 0.2,
    font        =\large,
    semithick,
  },
  leftrose/.style = {
    rose,
    fill = black!70,
  },
  rightrose/.style = {
    fill = black!10,
  },
}

\tikzset{
  pics/compassneedle/.style 2 args={
    code={
      %% Try to draw a needle by aims of polar coordinates.
      \filldraw[leftrose]
      % start at origin, 
      (0:0)
      % move nw for the short distance
      -- ({#1+45}:{\short*\needle})
      % reach the tip at north
      -- ({#1}:{\needle})
      % go back to origin
      -- cycle ;
      % repeat the same on the eastern side.
      \filldraw[rightrose]
      % start at origin, 
      (0:0)
      % move ne for the short distance
      -- ({#1-45}:{\short*\needle})
      % reach the tip at north
      -- ({#1}:{\needle})
      % go back to origin
      -- cycle ;
      %%
      %% Insert the direction
      \node[rotate={#1-90}] at ({#1}:{1.1*\needle}) {#2} ;
    }
  }, % end of compassneedle
}

\tikzset{%
  pics/compass/.style={
    code={
      %% Position a named node here
      \node (-compass) {};

      %% Begin with a layer of the rose pointing to ne, nw, sw, se.
      %% This layer shall be somewhat shorter than the main layer.
      \needlelength{3.5}
      \foreach \angle/\name in {45/NE, 135/NW, 225/SW, 315/SE} {
        \pic{compassneedle={\angle}{\name}} ;
      }
      %% Next, put a second layer with the main directions.  Don't
      %% forget to increase the needle lengths accordingly.
      \needlelength{4}
      \foreach  \angle/\name in {0/E, 90/N, 180/W, 270/S} {
        \pic{compassneedle={\angle}{\name}} ;
      }
    }
  },
}
\makeatletter

\begin{document}
\begin{figure}
    \resizebox{10cm}{!}{%
        \begin{tikzpicture}
            \pic (error) {compass} ;
            \pic [right=9cm of error-compass ] (error) {compass} ;
        \end{tikzpicture}
    }
\end{figure}
\end{document}

That way, you don't have the problem with the transform canvas={scale=...} where it has problems with the surroundings.

Edit: new way

\documentclass[12pt]{article}
\usepackage[ngerman]{babel}
\usepackage[T1]{fontenc}
\usepackage{tikz}
\usepackage{subfig} %% NEW PACKAGE
%% Lade weitere Pakete
\usetikzlibrary{
  positioning}
\def\needle{50}
\def\short{\needle/10}
\newcommand{\needlelength}[1]{\def\needle{#1}}
\tikzset{
  rose/.style = {
    % xscale      = 1/2,
    % yscale      = 1/2,
    % scale       = 0.2,
    font        =\large,
    semithick,
  },
  leftrose/.style = {
    rose,
    fill = black!70,
  },
  rightrose/.style = {
    fill = black!10,
  },
}
\tikzset{
  pics/compassneedle/.style 2 args={
    code={
      %% Try to draw a needle by aims of polar coordinates.
      \filldraw[leftrose]
      % start at origin, 
      (0:0)
      % move nw for the short distance
      -- ({#1+45}:{\short*\needle})
      % reach the tip at north
      -- ({#1}:{\needle})
      % go back to origin
      -- cycle ;
      % repeat the same on the eastern side.
      \filldraw[rightrose]
      % start at origin, 
      (0:0)
      % move ne for the short distance
      -- ({#1-45}:{\short*\needle})
      % reach the tip at north
      -- ({#1}:{\needle})
      % go back to origin
      -- cycle ;
      %%
      %% Insert the direction
      \node[rotate={#1-90}] at ({#1}:{1.1*\needle}) {#2} ;
    }
  }, % end of compassneedle
}
\tikzset{%
  pics/compass/.style={
    code={
      %% Position a named node here
      \node (-compass) {};

      %% Begin with a layer of the rose pointing to ne, nw, sw, se.
      %% This layer shall be somewhat shorter than the main layer.
      \needlelength{3.5}
      \foreach \angle/\name in {45/NE, 135/NW, 225/SW, 315/SE} {
        \pic{compassneedle={\angle}{\name}} ;
      }
      %% Next, put a second layer with the main directions.  Don't
      %% forget to increase the needle lengths accordingly.
      \needlelength{4}
      \foreach  \angle/\name in {0/E, 90/N, 180/W, 270/S} {
        \pic{compassneedle={\angle}{\name}} ;
      }
    }
  },
}
\makeatletter
\begin{document}
\begin{figure}
    \centering
    \subfloat{
        \raisebox{10mm}{
            \resizebox{3cm}{3cm}{
                \begin{tikzpicture}
                    \pic (error) {compass} ;
                \end{tikzpicture}
            }
        }
    }
    \subfloat{
        \resizebox{5cm}{5cm}{
            \begin{tikzpicture}
                \pic [right= 9cm of error-compass,anchor=center ] (error) {compass} ;
            \end{tikzpicture}
        }
    }
\end{figure}
\end{document}

Second way leads to

enter image description here

Hope that's what you're looking for.

2
  • this time the complete picture is scaled, instead of fitting only the compass part into it.
    – Jan
    Commented Apr 3, 2018 at 17:59
  • @Jan added a second answer.
    – Shade
    Commented Apr 3, 2018 at 18:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .