2

OK, I have some rather long code. I tried to reduce it as much as I could, but it's heavily tangled and I'm still not good in the usage of pgfkeys or xparse.

The problem: If the tikzpicture is rotated by any non-multiple of 90° the lines are off. If the tikzpicture is rotated by any multiple of 90° the lines are fine.

Why is that and how can i prevent it?

%%%%%%%%%%%%%% Common file
\documentclass{standalone}
\usepackage{etoolbox}

%Declare Macros for each floor to be defined by the building files. They are of the form: \ESKFPfloorEG, \ESKFPernEG, \ESKFPlabelsEG
\newcommand{\ESKFPcreatefloor}[1]{%
\expandafter\def\csname ESKFPfloor#1\endcsname{nothing defined}
}
\ESKFPcreatefloor{EG}

% Define Macros for the current floor to be used by the room files.
\newcommand{\ESKFPcurrentfloorcommand}{none}
\newcommand{\ESKFPsetfloor}[1]{%
\renewcommand{\ESKFPcurrentfloorcommand}{\csname ESKFPfloor#1\endcsname}
}

\newcommand{\ESKFPcurrentroom}{0}
\newcommand{\ESKFPsetroom}[1]{
\renewcommand{\ESKFPcurrentroom}{#1}
}
\newcommand{\ESKFPcurrentadditionaltext}{}


\newcommand{\ESKFPdoorata}{0}
\newcommand{\ESKFPdooratb}{0}
\newcommand{\ESKFPdooratc}{0}
\newcommand{\ESKFPdooratd}{0}
\newcommand{\ESKFPdoorapos}{\ifnumequal{\ESKFPdoorata}{1}{0.75}{0.25}}
\newcommand{\ESKFPdoorbpos}{\ifnumequal{\ESKFPdooratb}{1}{0.75}{0.25}}
\newcommand{\ESKFPdoorcpos}{\ifnumequal{\ESKFPdooratc}{1}{0.75}{0.25}}
\newcommand{\ESKFPdoordpos}{\ifnumequal{\ESKFPdooratd}{1}{0.75}{0.25}}
\newcommand{\ESKFPmisceins}{1}
\newcommand{\ESKFPmisczwei}{2}
\newcommand{\ESKFPmiscnull}{0}
\newcommand{\ESKFPcurrentexitdoorat}{0}

\newcounter{ESKFPcurrentdoor}
\setcounter{ESKFPcurrentdoor}{0}

\makeatletter
\long\def\ESKFPifnodedefined#1#2#3{%
    \@ifundefined{pgf@sh@ns@#1}{#3}{#2}%
}
\makeatother

\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{shapes.geometric}

\tikzset{%
every node/.style={outer sep=0pt},
ESKFPdoorcommonstyle/.style={%
 transform shape,
 text width=,
 circular sector,
 sloped,
 allow upside down,
 anchor=sector center,
 circular sector angle=90,
 draw,
 minimum size=200pt,
 },
ESKFPdoorstyle1/.style={%
 pos=#1,
 fill=yellow,
 ESKFPdoorcommonstyle,
 yscale=-1,
 rotate=45,
 },ESKFPdoorstyle1/.default=0.75,
ESKFPdoorstyle2/.style={%
 pos=#1,
 fill=blue,
 ESKFPdoorcommonstyle,
%  xscale=-1,
 rotate=225
 },ESKFPdoorstyle2/.default=0.25,
door1/.style={ESKFPdoorstyle1},
door2/.style={ESKFPdoorstyle2},
ESKFPnothighlightedstyle/.style={fill=white},
ESKFPhighlightedstyle/.style={fill=red},
ESKFPexitdoorstyle/.style={%
 alias=ESKFPcurrentexitdoor
 },
exitdoor/.style={ESKFPexitdoorstyle},
ESKFProomstyle/.style={ultra thick,fill=white,ESKFPcommonroomstyle},
ESKFPemptyroomstyle/.style={fill=none,ESKFPcommonroomstyle},
ESKFPcommonroomstyle/.style={draw},
ESKFPstairsstyle/.style={ultra thick,fill=green!80!black,ESKFPcommonroomstyle},
ESKFPelsestyle/.style={ESKFPcommonroomstyle},
stairs/.style={ESKFPelsestyle/.style={ESKFPstairsstyle}},
ESKFProomtextstyle/.style={inner sep=0pt,outer sep=0pt,font={\bfseries}},
ESKFPbackgroundstyle/.style={fill=green!50!white},
set door at 1/.code={\renewcommand{\ESKFPdoorata}{#1}},
set door at 2/.code={\renewcommand{\ESKFPdooratb}{#1}},
set door at 3/.code={\renewcommand{\ESKFPdooratc}{#1}},
set door at 4/.code={\renewcommand{\ESKFPdooratd}{#1}},
set door at 1/.default=1,
set door at 2/.default=1,
set door at 3/.default=1,
set door at 4/.default=1,
set exit door/.code={\renewcommand{\ESKFPcurrentexitdoorat}{#1}},
set exit door/.default=0,
set door 1 pos/.code={\renewcommand{\ESKFPdoorapos}{#1}},
set door 2 pos/.code={\renewcommand{\ESKFPdoorbpos}{#1}},
set door 3 pos/.code={\renewcommand{\ESKFPdoorcpos}{#1}},
set door 4 pos/.code={\renewcommand{\ESKFPdoordpos}{#1}},
set door 1 pos/.default=0.5,
set door 2 pos/.default=0.5,
set door 3 pos/.default=0.5,
set door 4 pos/.default=0.5,
}
%Layers of the Graphic
\pgfdeclarelayer{background}
\pgfdeclarelayer{rooms}
\pgfdeclarelayer{text}
\pgfdeclarelayer{test}
\pgfsetlayers{background,main,rooms,text,test}

%Highlightingstyle
\newcommand{\ESKFPdoifhighlighted}{%
\tikzset{ESKFPcurrentroomstyle/.style={ESKFPhighlightedstyle}}
}
\newcommand{\ESKFPdoifnothighlighted}{%
\tikzset{ESKFPcurrentroomstyle/.style={ESKFPnothighlightedstyle}}
}

\newcommand{\ESKFPcreateroom}[5][]{%#1=local tikz options,#2=name,#3=room number,#4=path with doors,#5=text coordinate
%The path has to be defined counter clockwise. Otherwise, the doors would be outside the room.
%To force the doors to be outside the room, use the option "shape border rotate=90" or "shape border rotate=270"
%If #5 is empty, than it is assumed, that the room has corners at the coordinates ESKFPc#2lu,ESKFPc#2ru, ESKFPc#2lo and ESKFPc#2ro and the text will be positioned at the barycentre of these 4 points. 

%Find out, if room has to be highlighted or not
\ifdefmacro{#2}%
{\ifdefstrequal{\ESKFPcurrentroom}{#2}{\ESKFPdoifhighlighted}{\ESKFPdoifnothighlighted}}
{\ifdefstring{\ESKFPcurrentroom}{#2}{\ESKFPdoifhighlighted}{\ESKFPdoifnothighlighted}}
%Apply given options in a local scope
\begin{scope}[#1]
\ifstrempty{#4}
{%
 \setcounter{ESKFPcurrentdoor}{0}
 \draw[ESKFProomstyle,ESKFPcurrentroomstyle,%
 to path=%
  {% the following adds the doors, if specified. This definition resides in the macros \ESKFPdoorata, \ESKFPdooratb, \ESKFPdooratc, \ESKFPdooratd and can have the values 1,2 or anything else
  \pgfextra{\stepcounter{ESKFPcurrentdoor}}
  \ifcsequal{ESKFPdoorat\alph{ESKFPcurrentdoor}}{ESKFPmisceins}
   {--node(ESKFProom#2door\the\value{ESKFPcurrentdoor})[door1,pos=\csname ESKFPdoor\alph{ESKFPcurrentdoor}pos\endcsname]{}(\tikztotarget)\tikztonodes}
   {%
    \ifcsequal{ESKFPdoorat\alph{ESKFPcurrentdoor}}{ESKFPmisczwei}
    {--node(ESKFProom#2door\the\value{ESKFPcurrentdoor})[door2,pos=\csname ESKFPdoor\alph{ESKFPcurrentdoor}pos\endcsname]{}(\tikztotarget)\tikztonodes}
    {--(\tikztotarget)\tikztonodes}
   }
  }
 ]%
 (ESKFPc#2lu)to(ESKFPc#2ru)to(ESKFPc#2ro)to(ESKFPc#2lo)to(ESKFPc#2lu)--cycle;
\ifnumgreater{\ESKFPcurrentexitdoorat}{0}
{\coordinate(ESKFProom#2exitdoor) at ($(ESKFProom#2door\ESKFPcurrentexitdoorat.sector center)!0.5!(ESKFProom#2door\ESKFPcurrentexitdoorat.arc start)$);}%Exit door is defined, that door will be used. It is assumed, that this door is indeed defined.
{%
 \renewcommand{\ESKFPcurrentadditionaltext}{Exit door guessed}
 \ESKFPifnodedefined{ESKFProom#2door1}{\coordinate(ESKFProom#2exitdoor) at ($(ESKFProom#2door1.sector center)!0.5!(ESKFProom#2door1.arc start)$);}
 {
  \ESKFPifnodedefined{ESKFProom#2door2}{\coordinate(ESKFProom#2exitdoor) at ($(ESKFProom#2door2.sector center)!0.5!(ESKFProom#2door2.arc start)$);}
  {
   \ESKFPifnodedefined{ESKFProom#2door3}{\coordinate(ESKFProom#2exitdoor) at ($(ESKFProom#2door3.sector center)!0.5!(ESKFProom#2door3.arc start)$);}
   {
    \ESKFPifnodedefined{ESKFProom#2door4}{\coordinate(ESKFProom#2exitdoor) at ($(ESKFProom#2door4.sector center)!0.5!(ESKFProom#2door4.arc start)$);}
    {
     \coordinate(ESKFProom#2exitdoor) at ($(ESKFPc#2lu)!0.5!(ESKFPc#2ro)$);
     \renewcommand{\ESKFPcurrentadditionaltext}{No exit door}
    }
   }
  }
 }
}
}
{%Path is supplied, especially a door with the style ESKFPexitdoorstyle must be given
%Also the coordinates ESKFPc[ROOMNAME]lu, ESKFPc[ROOMNAME]ru, ESKFPc[ROOMNAME]lo and ESKFPc[ROOMNAME]ro should be defined
 \draw[ESKFProomstyle,ESKFPcurrentroomstyle]{#4}--cycle;
 \coordinate(ESKFProom#2exitdoor) at (ESKFPcurrentexitdoor);
}

\ifstrempty{#5}
{\coordinate(ESKFProom#2textcenter) at ($0.25*(ESKFPc#2lu)+0.25*(ESKFPc#2ru)+0.25*(ESKFPc#2lo)+0.25*(ESKFPc#2ro)$);}
{\coordinate(ESKFProom#2textcenter) at #5;}

%Text (room number is set), the coordinate ESKFProom[ROOMNAME]textcenter is calculated before. This is #5 or is calculated from ESKFPc[ROOMNAME]lu, ESKFPc[ROOMNAME]ru, ESKFPc[ROOMNAME]lo and ESKFPc[ROOMNAME]ro if not given
\begin{pgfonlayer}{text}
\node[ESKFProomtextstyle](ESKFProom#2text) at (ESKFProom#2textcenter) {#3\ESKFPcurrentadditionaltext};
\end{pgfonlayer}
\end{scope}
}


\newcommand{\ESKFPcreateelse}[5][]{%#1=local tikz options,#2=name,#3=room number,#4=path with doors,#5=text coordinate
%The path has to be defined counter clockwise. Otherwise, the doors would be outside the room.
%To force the doors to be outside the room, use the option "shape border rotate=90" or "shape border rotate=270"
%If #5 is empty, than it is assumed, that the room has corners at the coordinates ESKFPc#2lu,ESKFPc#2ru, ESKFPc#2lo and ESKFPc#2ro and the text will be positioned at the barycentre of these 4 points. 

%Apply given options in a local scope
\begin{scope}[#1]
%Test if path is given
\ifstrempty{#4}
{%If Path is NOT given
 \setcounter{ESKFPcurrentdoor}{0}
 \draw[ESKFPelsestyle,%
 to path=%
  {% the following adds the doors, if specified. This definition resides in the macros \ESKFPdoorata, \ESKFPdooratb, \ESKFPdooratc, \ESKFPdooratd and can have the values 1,2 or anything else
  \pgfextra{\stepcounter{ESKFPcurrentdoor}}
  \ifcsequal{ESKFPdoorat\alph{ESKFPcurrentdoor}}{ESKFPmisceins}
   {--node(ESKFPstairs#2door\the\value{ESKFPcurrentdoor})[door1,pos=\csname ESKFPdoor\alph{ESKFPcurrentdoor}pos\endcsname]{}(\tikztotarget)\tikztonodes}
   {%
    \ifcsequal{ESKFPdoorat\alph{ESKFPcurrentdoor}}{ESKFPmisczwei}
    {--node(ESKFPstairs#2door\the\value{ESKFPcurrentdoor})[door2,pos=\csname ESKFPdoor\alph{ESKFPcurrentdoor}pos\endcsname]{}(\tikztotarget)\tikztonodes}
    {--(\tikztotarget)\tikztonodes}
   }
  }
 ]%
 (ESKFPc#2lu)to(ESKFPc#2ru)to(ESKFPc#2ro)to(ESKFPc#2lo)to(ESKFPc#2lu)--cycle;
}
{%If Path IS given. A door with the style ESKFPexitdoorstyle must be given
%Also the coordinates ESKFPc[ROOMNAME]lu, ESKFPc[ROOMNAME]ru, ESKFPc[ROOMNAME]lo and ESKFPc[ROOMNAME]ro should be defined
 \draw[ESKFPelsestyle]{#4}--cycle;
}

\ifstrempty{#5}%Test if coordinate for Text is given
{\coordinate(ESKFPstairs#2textcenter) at ($0.25*(ESKFPc#2lu)+0.25*(ESKFPc#2ru)+0.25*(ESKFPc#2lo)+0.25*(ESKFPc#2ro)$);}%If textcoordinate is NOT given
{\coordinate(ESKFPstairs#2textcenter) at #5;}%If textcoordinate is given
%Text (room number is set), the coordinate ESKFProom[ROOMNAME]textcenter is calculated before. This is #5 or is calculated from ESKFPc[ROOMNAME]lu, ESKFPc[ROOMNAME]ru, ESKFPc[ROOMNAME]lo and ESKFPc[ROOMNAME]ro if not given
\begin{pgfonlayer}{text}
\node[ESKFProomtextstyle](ESKFPstairs#2text) at (ESKFPstairs#2textcenter) {#3\ESKFPcurrentadditionaltext};
\end{pgfonlayer}
\end{scope}
}


%%%%%% Floor file

\newcommand{\ESKFPfloorGSEG}{%
\begin{scope}[scale=0.1]
%A101
\coordinate(ESKFPcA101lu) at (0,0);
\coordinate(ESKFPcA101ru) at (136,0);
\coordinate(ESKFPcA101ro) at (136,127);
\coordinate(ESKFPcA101lo) at (0,127);
%A102
\coordinate(ESKFPcA102lu) at (ESKFPcA101lo);
\coordinate(ESKFPcA102ru) at (ESKFPcA101ro);
\coordinate(ESKFPcA102lo) at ($(ESKFPcA101lo)+(0,90)$);
\coordinate(ESKFPcA102ro) at ($(ESKFPcA101ro)+(0,90)$);
%A103
\coordinate(ESKFPcA103lu) at (ESKFPcA102lo);
\coordinate(ESKFPcA103ru) at (ESKFPcA102ro);
\coordinate(ESKFPcA103lo) at ($(ESKFPcA102lo)+(0,90)$);
\coordinate(ESKFPcA103ro) at ($(ESKFPcA102ro)+(0,90)$);
%A104
\coordinate(ESKFPcA104lu) at (ESKFPcA103lo);
\coordinate(ESKFPcA104ru) at (ESKFPcA103ro);
\coordinate(ESKFPcA104lo) at ($(ESKFPcA103lo)+(0,120)$);
\coordinate(ESKFPcA104ro) at ($(ESKFPcA103ro)+(0,120)$);
%STA2CAFE
\coordinate(ESKFPcSTA2CAFElu) at ($(ESKFPcA104ro)+(0,-30)$);
\coordinate(ESKFPcSTA2CAFElo) at ($(ESKFPcA104ro)+(0,30)$);
\coordinate(ESKFPcSTA2CAFEru) at ($(ESKFPcSTA2CAFElu)+(120,0)$);
\coordinate(ESKFPcSTA2CAFEro) at ($(ESKFPcSTA2CAFElo)+(120,0)$);

%Rooms
\begin{pgfonlayer}{rooms}
%Left side
\ESKFPcreateroom[set door at 2,set exit door=2]{A101}{A101}{}{}
\ESKFPcreateroom[set door at 1,set door at 2=2,set exit door=2]{A102}{A102}{}{}
\ESKFPcreateroom[set door at 1,set door at 2,set exit door=2]{A103}{A103}{}{}
\ESKFPcreateroom[set door at 1,set door at 2=2,set exit door=2]{A104}{A104}{}{}
%Top side
\ESKFPcreateelse[stairs]{STA2CAFE}{To Cafeteria}{}{}
%
\ESKFPcreateelse{EMPTYA2CAFE}{}{(ESKFPcSTA2CAFElu)coordinate(ESKFPcEMPTYA2CAFElo)--++(0,-30)coordinate(ESKFPcEMPTYA2CAFElu)--node(ESKFPdoorEMPTYA2CAFEleft)[door2]{}node(ESKFPdoorEMPTYA2CAFEright)[door1]{}++(120,0)coordinate(ESKFPcEMPTYA2CAFEru)--++(0,30)coordinate(ESKFPcEMPTYA2CAFEro)}{(0,0)}%No Text to be set
%
\ESKFPcreateelse[stairs]{STAEG2AOGINEARCAFE}{Stairs}{($(ESKFPcSTA2CAFEro)+(0,-30)$)coordinate(ESKFPcSTAEG2AOGINEARCAFElo)--++(0,-120)coordinate(ESKFPcSTAEG2AOGINEARCAFElu)--node(ESKFPdoorSTAEG2AOGINEARCAFEleft)[door2]{}node(ESKFPdoorSTAEG2AOGINEARCAFEright)[door1]{}++(80,0)coordinate(ESKFPcSTAEG2AOGINEARCAFEru)--++(0,120)coordinate(ESKFPcSTAEG2AOGINEARCAFEro)--node(ESKFPdoorSTAEG2AOGINEARCAFEout)[door1,pos=0.25,rotate=180]{}(ESKFPcSTAEG2AOGINEARCAFElo)}{}
\end{pgfonlayer}
\end{scope}

%Backgroundlayer
\begin{pgfonlayer}{background}
\fill[ESKFPbackgroundstyle](ESKFPcA101lu)rectangle(ESKFPcSTAEG2AOGINEARCAFEro);
\end{pgfonlayer}
}
\let\ESKFPfloorEG\ESKFPfloorGSEG

%%%%%%%%%%%Actual Room file

\ESKFPsetfloor{EG}
\ESKFPsetroom{A102}

\begin{document}
\begin{tikzpicture}[mystyle/.style={ESKFPcurrentfloorstyle},rotate=45]
\ESKFPcurrentfloorcommand
\begin{pgfonlayer}{test}
\draw[red](ESKFProomA101exitdoor)to[in=0,out=0](ESKFProomA102exitdoor);
\end{pgfonlayer}
\end{tikzpicture}
\end{document}
2
  • 2
    Which lines are off?
    – Jake
    Jun 28, 2013 at 20:45
  • All the lines. If one compiles the file without rotate=45 in the tikzpicture, then there are no gaps between lines that should be equal. But if one compiles the file with rotate=45, then there are these gaps.
    – Toscho
    Jun 29, 2013 at 8:50

1 Answer 1

1

The problem seems to be floating point rounding when performing the calculations --- if one instead rotates the entire picture as a unit, rather than each individually, things seem to line up fine. Change line 294 to something like:

\rotatebox{13}{\begin{tikzpicture}[mystyle/.style={ESKFPcurrentfloorstyle}]

and close the group at the end of line 299:

\end{tikzpicture}}

and you'll be able to arbitrarily rotate it and still have things line up.

zoomed in on an area which was failing to align

2
  • OK, I also guessed, that it was about the rounding. I just didn't guess, that it would be clearly visible. The problem of your solution is, that the text rotates as well. This should not happen.
    – Toscho
    Jul 3, 2013 at 15:23
  • Okay, in that case, you'll need to apply the negative of the rotation to all the text elements in the tikz image (obviously) --- that's left as an exercise for the reader.
    – WillAdams
    Jul 3, 2013 at 15:38

You must log in to answer this question.

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