Menu

#484 Better grid operation

v1.0 (example)
closed-fixed
nobody
None
5
2019-01-02
2018-05-17
Kpym
No

The grid operation has several issues :

  • when xstep or ystep (resp. stepx or stepy in PGF) are set to 0 or negative the division or dimension error is thrown;
  • when we draw a grid like (1.5,1.5) grid (-2.5, -1.5) the end coordinate is set to (1, 1.5) which is the end of tha last drawn vertical line. Which is inconsistent with (0,0) rectangle (-2.5, -1.5).

As I don't see how to make a push request on sourceforge I submit here a purposal for a fix of \pgf@pathgrid that do the following :

  • Draw the vertical lines only if stepx > .01pt;
  • Draw the horizontal lines only if stepy > .01pt;
  • At end move the coordinate at the right position.
\documentclass[tikz,border=7pt]{standalone}
\makeatletter
\def\pgf@pathgrid[#1]#2#3{%
  \pgfset{#1}%
  \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/stepx}}%
  \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/stepy}}%
  \pgf@process{#3}%
  \pgf@xb=\pgf@x%
  \pgf@yb=\pgf@y%
  \pgf@process{#2}%
  \pgf@xa=\pgf@x%
  \pgf@ya=\pgf@y%
  % Swap coordinates if one of them is smaller than the other:
  \ifdim\pgf@xa>\pgf@xb%
    \pgf@x=\pgf@xb%
    \pgf@xb=\pgf@xa%
    \pgf@xa=\pgf@x%
  \fi%
  \ifdim\pgf@ya>\pgf@yb%
    \pgf@y=\pgf@yb%
    \pgf@yb=\pgf@ya%
    \pgf@ya=\pgf@y%
  \fi%
  \ifdim \pgf@yc > .01pt\relax% if to draw horizontal lines
    \c@pgf@counta=\pgf@ya\relax%
    \c@pgf@countb=\pgf@yc\relax%
    \divide\c@pgf@counta by\c@pgf@countb\relax%
    \pgfutil@tempdima=\c@pgf@counta\pgf@yc\relax%
    \ifdim\pgfutil@tempdima<\pgf@ya%
      \advance\pgfutil@tempdima by\pgf@yc%
    \fi%
    \pgfutil@tempdimb\pgf@x
    \pgfutil@loop% horizontal lines
      {%
        \pgf@xa=\pgfutil@tempdimb%
        \pgf@ya=\pgfutil@tempdima%
        \pgf@pos@transform{\pgf@xa}{\pgf@ya}
        \pgf@nlt@moveto{\pgf@xa}{\pgf@ya}%
        \pgf@xa=\pgf@xb%
        \pgf@ya=\pgfutil@tempdima%
        \pgf@pos@transform{\pgf@xa}{\pgf@ya}
        \pgf@nlt@lineto{\pgf@xa}{\pgf@ya}%
      }%
    \advance\pgfutil@tempdima by\pgf@yc%
    \ifdim\pgfutil@tempdima<\pgf@yb%
    \pgfutil@repeat%
    \advance\pgfutil@tempdima by-0.01pt\relax%
    \ifdim\pgfutil@tempdima<\pgf@yb%
      {%
        \pgf@xa=\pgfutil@tempdimb%
        \pgf@ya=\pgfutil@tempdima%
        \pgf@pos@transform{\pgf@xa}{\pgf@ya}
        \pgf@nlt@moveto{\pgf@xa}{\pgf@ya}%
        \pgf@xa=\pgf@xb%
        \pgf@ya=\pgfutil@tempdima%
        \pgf@pos@transform{\pgf@xa}{\pgf@ya}
        \pgf@nlt@lineto{\pgf@xa}{\pgf@ya}%
      }%
    \fi%
  \fi%
  \ifdim \pgf@xc > .01pt\relax% if to draw vertical lines
    \c@pgf@counta=\pgf@x\relax%
    \c@pgf@countb=\pgf@xc\relax%
    \divide\c@pgf@counta by\c@pgf@countb\relax%
    \pgfutil@tempdimb=\c@pgf@counta\pgf@xc\relax%
    \ifdim\pgfutil@tempdimb<\pgf@xa%
      \advance\pgfutil@tempdimb by\pgf@xc%
    \fi%
    \pgfutil@loop% vertical lines
      {%
        \pgf@xc=\pgfutil@tempdimb%
        \pgf@yc=\pgf@ya%
        \pgf@pos@transform{\pgf@xc}{\pgf@yc}
        \pgf@nlt@moveto{\pgf@xc}{\pgf@yc}%
        \pgf@xc=\pgfutil@tempdimb%
        \pgf@yc=\pgf@yb%
        \pgf@pos@transform{\pgf@xc}{\pgf@yc}
        \pgf@nlt@lineto{\pgf@xc}{\pgf@yc}%
      }%
      \advance\pgfutil@tempdimb by\pgf@xc%
    \ifdim\pgfutil@tempdimb<\pgf@xb%
    \pgfutil@repeat%
    \advance\pgfutil@tempdimb by-0.01pt\relax%
    \ifdim\pgfutil@tempdimb<\pgf@xb%
      {%
        \pgf@xc=\pgfutil@tempdimb%
        \pgf@yc=\pgf@ya%
        \pgf@pos@transform{\pgf@xc}{\pgf@yc}
        \pgf@nlt@moveto{\pgf@xc}{\pgf@yc}%
        \pgf@xc=\pgfutil@tempdimb%
        \pgf@yc=\pgf@yb%
        \pgf@pos@transform{\pgf@xc}{\pgf@yc}
        \pgf@nlt@lineto{\pgf@xc}{\pgf@yc}%
      }%
    \fi%
  \fi%
  \pgf@process{#3}%
  \pgf@pos@transform{\pgf@x}{\pgf@y}%
  \pgf@nlt@moveto{\pgf@x}{\pgf@y}%
}
\makeatother

\begin{document}
  \begin{tikzpicture}
    \begin{scope}[rotate=30]
      \draw[help lines, red] (0,0) node[right]{(0,0)} rectangle (-5,5) node[left]{(-5,5)};
      \draw[xstep=21pt, ystep=0mm,ultra thick] (0,0) grid (-5,5) -- ++(30:1);
    \end{scope}
  \end{tikzpicture}
\end{document}

Note: The arbitrary .01pt can be replaced by the more logical \pgflinewidth but what if \pgflinewidth=0...

Related

Bugs: #1

Discussion

  • Stefan Pinnow

    Stefan Pinnow - 2018-05-29
    • status: open --> closed-fixed
     
  • Stefan Pinnow

    Stefan Pinnow - 2018-05-29

    Many thanks for reporting and providing the patch, which is now included to the code.

     
  • Kpym

    Kpym - 2018-05-29

    Thanks for considering my merge request. It's nice to now that we can help the project we like.

     

    Last edit: Kpym 2018-05-29
  • Christian Feuersänger

    Unfortunately, the fix breaks nonlinear transformations, for example

    \documentclass{article}
    
    \usepackage{tikz}
    \usepgflibrary{curvilinear}
    \usepgfmodule{nonlineartransformations}
    
    \begin{document}
    
    \makeatletter
    \begin{tikzpicture}
      \draw [help lines] (0,0) grid (3,2);
      {
        \pgfsetcurvilinearbeziercurve
          {\pgfpoint{0mm}{20mm}}
          {\pgfpoint{11mm}{20mm}}
          {\pgfpoint{20mm}{11mm}}
          {\pgfpoint{20mm}{0mm}}
        \pgftransformnonlinear{\pgfpointcurvilinearbezierorthogonal\pgf@x\pgf@y}%
        \draw (0,-30pt) grid [step=10pt] (80pt,30pt);
      }
      \draw[red, very thick]
        (0mm,20mm) .. controls (11mm,20mm) and (20mm,11mm) .. (20mm,0mm);
    \end{tikzpicture}
    
    \end{document}
    

    in this case, the grid lines are not transformed properly.

    I will roll back the change for now and reopen the issue until we have time to fix it (as we do not want to break the existing functionality as part of the next release)

     

    Last edit: Christian Feuersänger 2019-01-01
  • Christian Feuersänger

    • status: closed-fixed --> open
     
  • Christian Feuersänger

    The problem affects examples in the manual, see documentation for the curvilinear library in Section 107.4.7

     
  • Christian Feuersänger

    The commit which introduced the faulty version was 0a65c10132098c5b4f035b3df1e0df393eac218b
    my revert is 92735cd0884112dc439854061acd5a427f92eacd

     
  • Kpym

    Kpym - 2019-01-01

    The error comes from bad copy/paste in the code (I think) :(
    The faulty line is 1187 with the code

    \c@pgf@counta=\pgf@x\relax%
    

    This line should simply be deleted.

    The code is supposed to do only three things :

    • check that the y step is positive

      ~~~
      \ifdim \pgf@yc > .01pt\relax% if to draw horizontal lines
      ...
      \fi%
      ~~~
      
    • check that the x step is positive

      ~~~
      \ifdim \pgf@xc > .01pt\relax% if to draw vertical lines
      ...
      \fi%
        ~~~
      
    • and move at the destination position at the end

        ~~~
        \pgf@process{#3}%
        \pgf@pos@transform{\pgf@x}{\pgf@y}%
        \pgf@nlt@moveto{\pgf@x}{\pgf@y}%
        ~~~
      

    So I don't know why this line was added there, but it is probably a copy/paste error.
    There is a similar line after the first check (that was already in the code) but this second change of \c@pgf@counta is not in the original code ... so there is no reason to be in the new code.
    Sorry for that.

     
  • Kpym

    Kpym - 2019-01-01

    I made a new merge request with the modified line 1187.

    Now I partially remember why this line was changed : it is not a copy paste error.

    The original code was : \c@pgf@counta=\pgfutil@tempdimb\relax% but as \pgfutil@tempdimb is set to be \pgf@x in the \ifdim part for the y step I was thinking that if this code is not executed (in the case \pgf@yc is 0 for example) in place to set \c@pgf@counta from \pgfutil@tempdimb it should be set to \pgf@x ... I was wrong.

    To be honest I do not understand in the case [ysetp=0] what is the value of \pgfutil@tempdimb, but all my tests confirm that it works properly with ou without non linear transform.

     
  • Christian Feuersänger

    Excellent, thanks for the analysis and the fast response. The example appears to work and your revised fix is now part of PGF.

    Thanks again for contributing!

     
  • Christian Feuersänger

    • status: open --> closed-fixed
     
  • Kpym

    Kpym - 2019-01-02

    The "new" line 1187 is not good. I have made another merge requaest.

    Let me explain :

    • in the original version this line was \c@pgf@counta=\pgfutil@tempdimb\relax% and is used in a calculation to check from where to start the loop, because the first line is not necessarilly stratong from the starting point. But in this version at this moment \pgfutil@tempdimb has the same value as \pgf@xa, which is more natural to be used here. And when there is no nolinear transform \pgf@xa is also equa to \pgf@x.
    • in my first attempt I replaced \pgfutil@tempdimb by \pgf@x which was backward incompatible in the case of nonlinear transform.
    • in my second attempt I returned back to \pgfutil@tempdimb which was backward compatible (in the case ysetp > 0) but is not good in the case ystep=0.
    • now I replace \pgfutil@tempdimb by \pgf@xa which seems to be backward compatible and consistent with the new behaviour when ystep=0.

    Sorry for this mess, but to be honnest the original code is not very clean at ths place :(

     
  • Stefan Pinnow

    Stefan Pinnow - 2019-01-02

    Thank you for the follow-up. I merged your fixed code.

     
    • Kpym

      Kpym - 2019-01-02

      Thanks. I hope that will be the end of this Ticket :)