3

Uniform grid on distorted axes

I want to draw a square discretised by equally spaced lines. However, if I move one of the nodes, say node 4, the grid lines will keep it's relative spacing (see the image). I have no idea what to search for. One idea would be to calculate coordinates on the path (1)--(4) and (4)--(3), then re-calculate the coordinates when ever I move node 4 before I draw lines between the two opposite sides. I'm wondering if there is a better way to do this.

Many thanks.

  • Assuming you are using tikz, then \foreach\x={0,1,2,...,8}{\draw ($(1)!{\x/8}!(4)$) -- ($(2)!{\x/8}!(3)$);} or something like that. – John Kormylo Sep 28 '15 at 21:27
  • Welcome! Please post the code you have, even if it is for just the non-distorted square. It is easier to help you if we start from the point where you get stuck. – cfr Sep 28 '15 at 21:42
  • @JohnKormylo Sounds like an answer, doesn't it? ;) – Gonzalo Medina Sep 28 '15 at 21:47
  • Sorry, I should have been more specific. Yes, I'm using tikz. Currently trying to understand the bit in between the two dollar signs. Thank you all so much for replying. @cfr: I will definitely do next time. Sorry, it's my first time posting and using this place, I didn't think I should post my obviously less efficient attempts. – Rawhy Sep 29 '15 at 22:28
  • 1
    @RaymonWhite If you want, I finally improved the code to draw the grid automatically! – MarcoG Oct 5 '15 at 14:13
6

Here is my attempt. Initially I started looking for a solution similar to the one proposed by John Kormylo in his comment, and ended up using the decorations.markings library. I hope it is not such an overkill :-) ! In every case the grid is self-adapting, as you can see from the following images:

enter image description hereenter image description hereenter image description here enter image description here

My code is:

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{decorations.markings}

\def\NrLines{8}
\pgfmathsetmacro{\UnitSegment}{1/(\NrLines+1)}

\begin{document}
\begin{tikzpicture}[draw=red]

% Nodes definition
\node[inner sep=0pt,minimum size=0pt,label=below:1] (a) at (2,5) {};
\node[inner sep=0pt,minimum size=0pt,label=below:2] (b) at (5,1) {};
\node[inner sep=0pt,minimum size=0pt,label=above:3] (c) at (6,2) {};
\node[inner sep=0pt,minimum size=0pt,label=above:4] (d) at (5,3) {};

% Paths between nodes
\draw [postaction={decorate},decoration={markings,
mark=between positions 0 and 1 step \UnitSegment with {
\node [inner sep=0pt,minimum size=0pt,
name=mark-1-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}]
{};}}] (a) -- (b);

\draw [postaction={decorate},decoration={markings,
mark=between positions 0 and 1 step \UnitSegment with {
\node [inner sep=0pt,minimum size=0pt,
name=mark-2-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}]
{};}}] (b) -- (c);

\draw [postaction={decorate},decoration={markings,
mark=between positions 0 and 1 step \UnitSegment with {
\node [inner sep=0pt,minimum size=0pt,
name=mark-3-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}]
{};}}] (c) -- (d);

\draw [postaction={decorate},decoration={markings,
mark=between positions 0 and 1 step \UnitSegment with {
\node [inner sep=0pt,minimum size=0pt,
name=mark-4-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}]
{};}}] (d) -- (a);

% Grid
\draw (mark-1-2) -- (mark-3-9);
\draw (mark-1-3) -- (mark-3-8);
\draw (mark-1-4) -- (mark-3-7);
\draw (mark-1-5) -- (mark-3-6);
\draw (mark-1-6) -- (mark-3-5);
\draw (mark-1-7) -- (mark-3-4);
\draw (mark-1-8) -- (mark-3-3);
\draw (mark-1-9) -- (mark-3-2);

\draw (mark-2-2) -- (mark-4-9);
\draw (mark-2-3) -- (mark-4-8);
\draw (mark-2-4) -- (mark-4-7);
\draw (mark-2-5) -- (mark-4-6);
\draw (mark-2-6) -- (mark-4-5);
\draw (mark-2-7) -- (mark-4-4);
\draw (mark-2-8) -- (mark-4-3);
\draw (mark-2-9) -- (mark-4-2);

% Nodes circles
\foreach \a in {a,...,d}{%
    \fill[black] (\a) circle (2pt);
}

\end{tikzpicture}
\end{document}

In this code \NrLines is defined as the number of internal lines, which are separated by a distance equal to \UnitSegment.

Unfortunately I could not find a way to draw the grid automatically; I tried with:

\pgfmathsetmacro{\End}{\NrLines+1}

\foreach \x in {1,2}{%
    \pgfmathsetmacro{\y}{\x+2}
    \foreach \i/\j in {2/\End,...,\End/2}{%
        \draw (mark-\x-\i) -- (mark-\y-\j);
    }
}

but there was a problem with using the result of \pgfsetmacro{} inside a node name. Maybe someone more expert than me may suggest a solution to use this \foreach loop.

EDIT: Finally, I improved the code to draw the grid automatically! There were two issues:

  • the use of \pgfmathsetmacro inside a node name, solved thanks to Stefan Kottwitz's answer "Pointing to a node with calculated name, why do I get to the east, not to the center?": instead of pgfmathsetmacro, one should use \pgfmathtruncatemacro to remove decimal points in the result;
  • the internal \foreach loop can not work using \foreach \i/\j in {2/\End,...,\End/2} since it is not clear (for the solver :-) ) how \i and \j are changing. Therefore, \j is evaluated in each step as a function of \i, which is the only counter for the loop.

The new improved code is:

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{decorations.markings}

\def\NrLines{8}
\pgfmathsetmacro{\UnitSegment}{1/(\NrLines+1)}
\pgfmathsetmacro{\End}{\NrLines+1}

\begin{document}
\begin{tikzpicture}[draw=red]

% Nodes definition
\node[inner sep=0pt,minimum size=0pt,label=below:1] (a) at (2,0) {};
\node[inner sep=0pt,minimum size=0pt,label=below:2] (b) at (5,0) {};
\node[inner sep=0pt,minimum size=0pt,label=above:3] (c) at (4,3) {};
\node[inner sep=0pt,minimum size=0pt,label=above:4] (d) at (3,3) {};

% Paths between nodes
\draw [postaction={decorate},decoration={markings,
mark=between positions 0 and 1 step \UnitSegment with {
\node [inner sep=0pt,minimum size=0pt,
name=mark-1-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}]
{};}}] (a) -- (b);

\draw [postaction={decorate},decoration={markings,
mark=between positions 0 and 1 step \UnitSegment with {
\node [inner sep=0pt,minimum size=0pt,
name=mark-2-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}]
{};}}] (b) -- (c);

\draw [postaction={decorate},decoration={markings,
mark=between positions 0 and 1 step \UnitSegment with {
\node [inner sep=0pt,minimum size=0pt,
name=mark-3-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}]
{};}}] (c) -- (d);

\draw [postaction={decorate},decoration={markings,
mark=between positions 0 and 1 step \UnitSegment with {
\node [inner sep=0pt,minimum size=0pt,
name=mark-4-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}]
{};}}] (d) -- (a);

% Grid
\foreach \x in {1,2}{%
    \pgfmathtruncatemacro{\y}{\x+2}
    \foreach \i in {2,...,\End}{%
        \pgfmathtruncatemacro{\j}{\End-\i+2}
        \draw (mark-\x-\i) -- (mark-\y-\j);
    }
}

% Nodes circles
\foreach \a in {a,...,d}{%
    \fill[black] (\a) circle (2pt);
}

\end{tikzpicture}
\end{document}

Now you can easily modify the grid setting the number of internal lines \NrLines, and the code will work without problems!

  • Thank you, this was exactly what I was hoping to do! Working from your example, I'm now trying to add an extra node at the centroid and make the grid move with that (whilst keeping all other nodes still). I have no idea how hard this would be. – Rawhy Sep 29 '15 at 23:03
  • 1
    @RaymonWhite you're welcome! If you have some question about my solution, feel free to ask! I'm not sure of what you mean with "make the grid move with the centroid". If it is worth it, you could open a follow up question. – MarcoG Sep 30 '15 at 5:15
  • Hi, thank you for improving the code! I'll look at it later on tonight. By "centroid" I mean, to place a node right in the middle of the square (the centoid), or on a mid-edge (say between node 1 and node 2). Then imagine if I were to drag that new node around and keep all other nodes fixed. The grid will distort accordingly. For now, in my thesis, I've just described the effects in words, not attempted to draw it yet. I want to get this thesis finished, I'll come back to it when I have time at the end. – Rawhy Oct 5 '15 at 17:47
  • @RaymonWhite you're welcome! I think that for the centroid it is worth opening a new question, since it seems not so trivial :-) ! – MarcoG Oct 6 '15 at 17:11
10

Here's one better way, using Metapost, using the point x of y notation. TikZ has the same idea, but using a rather more compact notation. With this set up you can move your four points as much as you like, and the grid will adapt itself accordingly.

enter image description here

prologues := 3;
outputtemplate := "%j%c.eps";

beginfig(1);

z1 = origin;
z2 = (80,0);
z3 = (96,80);
z4 = (-10,40);

n = 8;

for i=0 upto n:
  draw point i/n of (z1--z2) -- point i/n of (z4--z3) withcolor .67 red;
  draw point i/n of (z1--z4) -- point i/n of (z2--z3) withcolor .67 red;
endfor

dotlabel.llft("1", z1);
dotlabel.lrt ("2", z2);
dotlabel.urt ("3", z3);
dotlabel.ulft("4", z4);

endfig;
end.

Now I've moved z3 and z4 a bit, but changed nothing else.

enter image description here

  • Thank you @Thruston for the reply. I've not heard of Metapost before. I'll look into it as soon as I'm done with this report. The solution you've provided really does look elegant compared to my initial solution in tikz. – Rawhy Sep 29 '15 at 23:15
7

A generalisation of John Kormylo's comment above, all tied up in pic.

\documentclass[tikz, border=5]{standalone}
\usetikzlibrary{calc}
\tikzset{pics/.cd,
grid/.style args={(#1)#2(#3)#4(#5)#6(#7)#8}{code={%
\tikzset{pics/grid/dimensions=#8}%
\foreach \i in {0,...,\y}
  \draw [pic actions/.try] ($(#1)!\i/\y!(#7)$) -- ($(#3)!\i/\y!(#5)$);
\foreach \i in {0,...,\x}
  \draw [pic actions/.try] ($(#1)!\i/\x!(#3)$) -- ($(#7)!\i/\x!(#5)$);
\path (#1) coordinate (-1) (#3) coordinate (-2)
      (#5) coordinate (-3) (#7) coordinate (-4);
}},
grid/dimensions/.code args={#1x#2}{\def\x{#1}\def\y{#2}}}
\begin{document}
\begin{tikzpicture}
\pic (A) at (0,0) [black] {grid={(0,0) (4,0)  (4,4) (0,4)  8x8}};
\pic (B) at (7,0) [red]   {grid={(0,0) (4,0)  (4,3) (0,5)  8x8}};
\pic (C) at (0,7) [green] {grid={(0,0) (4,0)  (5,5) (0,3)  8x8}};
\pic (D) at (7,7) [blue]  {grid={(0,0) (3,-1) (4,5) (-1,3) 8x8}};
\foreach \i in {A,...,D}
  \foreach \j in {1,...,4}
    \fill (\i-\j) circle [radius=.1] node [anchor=\j*90-45] {\j};
\end{tikzpicture}
\end{document}

enter image description here

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.