4

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.

6
  • 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. Sep 28, 2015 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, 2015 at 21:42
  • @JohnKormylo Sounds like an answer, doesn't it? ;) Sep 28, 2015 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, 2015 at 22:28
  • 1
    @RaymonWhite If you want, I finally improved the code to draw the grid automatically!
    – MarcoG
    Oct 5, 2015 at 14:13

3 Answers 3

7

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!

4
  • 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, 2015 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, 2015 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, 2015 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, 2015 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

1
  • 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, 2015 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

0

You must log in to answer this question.

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