Wenn ich in einer tikz Abbildung die Verbindung zwischen zwei Koordinaten zeichne, dann liegt die Verbindungslinie zwischen beiden in der Mitte der gezeichneten Linie. Besonders deutlich wird das, wenn ich zunächst eine sehr breite Linie und anschließend noch eine dünne darüber zeichne.

Das erklärt, warum ein Rechteck, dessen linke und rechte Eckkoordinaten einen horizontalen Abstand von \linewidth haben,nach dem Zeichnen um eine ganze Liniendicke (\pgflinewidth der gezeichneten Linie) zu breit ist: die vertikalen Linien benötigen jeweils 0.5\pgflinewidth zusätzlich.

Aber auch wenn ich nur eine horizontale Linie der Länge \linewidth zeichne, ist die Abbildung hinterher um eine ganze Liniendicke (\pgflinewidth der gezeichneten Linie) zu breit. Warum? Wie kann ich das korrigieren?

\documentclass[parskip=full-]{scrartcl} 
\usepackage{tikz}
\usepackage{showframe} % Seitenlayout anzeigen

\begin{document} 
\minisec{Rechteck}
\begin{tikzpicture}
  \draw[line width=2cm,blue!50](0,0)rectangle(\linewidth,5cm);
  \draw[very thick,red](0,0)rectangle(\linewidth,5cm);
\end{tikzpicture}

\minisec{Sehr dicke horizontale Linie}
\begin{tikzpicture}
  \draw[line width=2cm,green!50](0,0)--(\linewidth,0);
  \draw[very thick,red](0,0)--(\linewidth,0);
\end{tikzpicture}

Mit gezeichneter Bounding Box

\begin{tikzpicture}
  \draw[line width=2cm,green!50,use as bounding box](0,0)--(\linewidth,0);
  \draw[red](current bounding box.south west)rectangle(current bounding box.north east);
\end{tikzpicture}
\end{document}

alt text

gefragt 11 Dez '13, 11:38

welle's gravatar image

welle
106222631
Akzeptiert-Rate: 0%


Wenn TikZ die Bounding Box zu einem Pfad ermittelt, dann werden von jeder Koordinate, die auf dem Pfad erreicht wird, die x- und die y-Werte überprüft, ob sie außerhalb der aktuellen (Pfad-)Bounding Box liegen. Nach dem der Pfad konstruiert wurde, wird (in \pgfusepath) überprüft, ob der Pfad auch gezeichnet werden soll (und nicht nur gefüllt o.Ä.).

Falls dies der Fall ist, fügt PGF der Bounding Box auf allen Seiten .5\pgflinewidth hinzu, da das Bild ja nicht nur aus dem Pfad besteht, sondern auch noch aus der Linie, die ja eine gewisse Breite hat.

Das funktioniert für den Fall des (unrotierten) Rechtecks optimal, da wir ja tatsächlich auf allen Seite genau eine halbe Linienbreite „über“ haben. PGF unterscheidet allerdings nicht zwischen dem Rechteck und der horizontalen Linie (die ja im Prinzip auch nur ein gefülltes Rechteck darstellt). So passiert es, dass an beiden Seiten .5\pgflinewidth Luft entsteht.

Es kann aber übrigens noch schlimmer sein:

\draw[line width=1cm, blue!50] (2,1) -- (0,0) -- (2,0);

alt text

Die gestrichelte Linie ist die Pfad-Bounding-Box vor dem Expandieren. Die gepunktete Linien zeigen an, wo die Koordinaten des Pfades liegen und deuten den Abstand .5\pgflinewidth an.

Der Algorithmus ist hier nicht sehr intelligent:

  • Er fügt die halbe Linienbreite ein, obwohl die Linie stumpf endet (line cap=butt).
  • Er fügt (nur) die halbe Linienbreite ein, wenn man mit line cap=rect das obige Verhalten vermeintlich korrigieren will:

    alt text

  • Bei einem miter-Line-Join versagt es total.

(Das obige Beispiel würde mit line join=bevel ohne Probleme in die Bounding Box passen, genauso wie mit \line cap=round, line join=round.)

Bis auf aufwändige manuelle Korrekturen (sofern sie denn überhaupt notwendig sind) kann man hier im Allgemeinen nicht helfen.


Für deinen Fall bietet es sich an die Keys trim left und trim right zu verwenden, um die horizontale Maße des fertigen TikZ-Pictures zu manipulieren. Dafür reicht bereits

trim left=+0cm, trim right=+\linewidth

in dem optionalen Argument von \begin{tikzpicture}. Wir erhalten dann:

alt text

(Meta: Die Linien von showframe sind außen an der Text-Box dran um nicht mit halber Linienbreite in den Text-Bereich hereinzuragen, werden aber nach dem Text gezeichnet.)

Man beachte das untere Beispiel stark herangezoomt, die Linie berührt den Rand nur. (Mit \usepackage[showframe,pass]{geometry} lässt sich das eventuell besser beobachten.)


Ein anderer Lösungsansatz versucht das zu lösen, in dem es die abschließende Überprüfung und das Hinzufügen von .5\pgflinewidth verhindert, was mit

\tikz@addmode{\pgf@relevantforpicturesizefalse}

geschehen kann. Der Switch \pgf@relevantforpicturesizefalse ist quasi die PGF-Version vom overlay-Key. Fügt man es als mode hinzu, wird es erst aktiv, wenn der Pfad gezeichnet, aber nicht konstruiert wird. Dies kann man ebenso im overlay-Key verpacken:

\makeatletter
\tikzset{
  overlay/.is choice,
  overlay/.default=true,
  overlay/true/.code=\pgf@relevantforpicturesizefalse,
  overlay/line width/.code=% oder "line width true"?
    \tikz@addmode{\pgf@relevantforpicturesizefalse},
  overlay/false/.code=\pgf@relevantforpicturesizetrue,
  overlay/line width false/.code=\tikz@addmode{\pgf@relevantforpicturesizetrue}}
\makeatother

Dies erlaubt nun die Verwendung von overlay=line width auf einem Pfad, bei dem die Linienbreite schlichtweg ignoriert werden soll. Aber Vorsicht! Das ignoriert die Linienbreite auch in vertikaler Richtung. Bei dem Fall einer horizontalen Linie haben wir dann nur noch eine Bounding Box, die keine Höhe hat (und der roten Linie in dem oberen Beispiel mit der dicken Linie entspricht):

alt text


Wenn du den line cap=recht verwendest, kannst du übrigens auch einfach die Linienbreite beim zeichnen abziehen:

\draw[line width=2cm, line cap=rect] (0,0) -- (\linewidth-\pgflinewidth,0);
Permanenter link

beantwortet 11 Dez '13, 13:46

Qrrbrbirlbel's gravatar image

Qrrbrbirlbel
2.9k2815
Akzeptiert-Rate: 53%

bearbeitet 11 Dez '13, 13:48

Man kann overlay=line width imitieren ohne Neudefinition von overlay, in dem man einfach [overlay] am Ende des Pfades verwendet, so dass die Option nur noch gesetzt wird, wenn der Pfad gezeichnet wird (und nicht konstruiert).

(11 Dez '13, 19:03) Qrrbrbirlbel

Ich denke die Kapitel 15.7 und 15.3.1 im pgf-Manual erklären die Situation. TikZ ist ganz gut darin die Bounding-Boxes selbst festzulegen, macht es aber nicht in allen Situationen fehlerfrei. Eine solche Situation hast du hier. Da es mit /tikz/line cap verschiedene Linien-Enden gibt, nimmt TikZ den Fall an, der am meisten Platz braucht. Wenn es wichtig ist, dass dein Bild weniger Platz einnimmt musst du mit \useasboundingbox selbst Hand anlegen:

\documentclass[parskip=full-]{scrartcl} 
\usepackage{tikz}
\usepackage{showframe} % Seitenlayout anzeigen

\begin{document} 
\minisec{Zwei dicke horizontale Linien}
\begin{tikzpicture}
\begin{scope}
  \useasboundingbox(0,-1)rectangle(\linewidth,1);
  \draw[line width=2cm,green!50](0,0)--(\linewidth,0);
\end{scope}  
  \draw[line width=2cm,green!50](2,3)--(\linewidth-2cm,3);
\end{tikzpicture}
\end{document}

DickeLinien

Innerhalb eines scope oder eines tikzpicture werden die Bounding-Boxes solange addiert, bis eine Bounding-Box manuell festgelegt wird. Um nun nur für eine Linie die Bounding-Box zu korrigieren, muss diese in ein scope eingeklammert werden.

Abhängig davon, was du letztendlich erreichen willst, gibt es auch noch andere Möglichkeiten. Zum Beispiel ein Rechteck zu füllen oder einen Clip zu verwenden:

\begin{tikzpicture}
  \fill[green!50](0,0)rectangle(\linewidth,2);
\end{tikzpicture}

\begin{tikzpicture}
  \clip(0,-1)rectangle(\linewidth,1);
  \draw[line width=2cm,green!50](0,0)--(\linewidth,0);
\end{tikzpicture}
Permanenter link

beantwortet 11 Dez '13, 12:59

sudo's gravatar image

sudo
2.0k51421
Akzeptiert-Rate: 39%

bearbeitet 11 Dez '13, 15:46

Deine Antwort
Vorschau umschalten

Folgen dieser Frage

Per E-Mail:

Wenn sie sich anmelden, kommen Sie für alle Updates hier in Frage

Per RSS:

Antworten

Antworten und Kommentare

Markdown-Grundlagen

  • *kursiv* oder _kursiv_
  • **Fett** oder __Fett__
  • Link:[Text](http://url.com/ "Titel")
  • Bild?![alt Text](/path/img.jpg "Titel")
  • nummerierte Liste: 1. Foo 2. Bar
  • zum Hinzufügen ein Zeilenumbruchs fügen Sie einfach zwei Leerzeichen an die Stelle an der die neue Linie sein soll.
  • grundlegende HTML-Tags werden ebenfalls unterstützt

Frage-Themen:

×728

gestellte Frage: 11 Dez '13, 11:38

Frage wurde gesehen: 11,027 Mal

zuletzt geändert: 11 Dez '13, 19:03