2
2

Auf golatex.de habe ich folgende, mir interessant erscheinende Frage gesehen:

Wie kann ich möglichst einfach die Fläche zwischen drei sich schneidenden Pfaden füllen, wenn diese Pfade keine Geraden sind?

Open in writeLaTeX
\documentclass[margin=5mm,tikz]{standalone}
\usetikzlibrary{intersections}
\begin{document} 
\begin{tikzpicture}
  \draw [name path=line1] (1,1) .. controls (3,4) .. (10,5) ; 
  \draw [name path=line2] (2,5) .. controls (6,5) .. (10,1) ; 
  \draw [name path=line3] 
    (1,2) .. controls (3,3) and (7,0) .. (9,2) ..controls (10,3.5) .. (10,3.5) ; 
\end{tikzpicture} 
\end{document}

alt text

gefragt 01 Apr '14, 11:42

esdd's gravatar image

esdd
14.2k53251
Akzeptiert: 87%

bearbeitet 02 Apr '14, 15:08

stefan's gravatar image

stefan ♦♦
5.8k12134

Die Frage ist zum Archivieren gedacht, kein Support benötigt. Ich antworte zwar auch selbst, aber mich würden Alternativen sehr interessieren.

(01 Apr '14, 11:42) esdd

Gute Frage, ich bin schon sehr auf die Antwort gespannt.

(01 Apr '14, 12:14) Johannes

pgfplots kommt mit der fillbetween library, die eigentlich fuer plots gedacht ist, aber auch ein tikz interface hat. Aktuell muss man dazu pgfplots laden (vielleicht faellt das irgendwann weg).

Die Idee ist, dass man intersection segments angibt, und damit paarweise segmente verbindet. Der grosse Vorteil dieses Ansatzes: die Komplexitaet der Schnittpunktsberechnung und der Berechnung der Pfade dazwischen wird von fillbetween erledigt; man muss nur noch sagen, welche schnittsegmente man in welcher Reihenfolge konkatenieren will.

Da hier drei Pfade beteiligt sind und fillbetween immer nur zwei kombinieren kann, muss man das Schrittweise machen:

Open in writeLaTeX
\documentclass[margin=5mm,tikz]{standalone}
\usetikzlibrary{intersections}
\usepackage{pgfplots}
\usepgfplotslibrary{fillbetween}

\begin{document} 
\begin{tikzpicture}
  \pgfdeclarelayer{pre main}
  \pgfsetlayers{pre main,main}
  \draw [red,name path=line1] (1,1) .. controls (3,4) .. (10,5) ; 
  \draw [green,name path=line2] (2,5) .. controls (6,5) .. (10,1) ; 
  \draw [name path=line3] 
    (1,2) .. controls (3,3) and (7,0) .. (9,2) ..controls (10,3.5) .. (10,3.5) ; 
  \path [%draw,line width=3,blue,
    name path=1and3,
    intersection segments={
        of=line1 and line3,
        sequence={A1[reverse] -- B1}
    }];

  \pgfonlayer{pre main}
  \fill [
    blue!40!white,
    intersection segments={
        of=1and3 and line2,
        sequence={A1 -- B1[reverse]},
    }
  ];
  \endpgfonlayer

\end{tikzpicture} 
\end{document}

alt text

Der key intersection segments erwartet notwendig of=pfad1 and pfad2 und sequence. Zweiteres ist das interessante: Man kann darin die segmente des ersten Pfads mit A<index> verwenden, wobei <index>=0,1,...,n oder * ist. Dasselbe geht mit den den segmenten des zweiten Pfads, der dann nicht mit A sondern mit B<index> referenziert wird. Hinter jedes Segment kann man die Option reverse angeben, also heisst A1[reverse] soviel wie "nehme das zweite segment (index 1) vom ersten Pfad (A) und drehe die Reihenfolge um".

Mit \path ... ; habe ich einen Pfad gemacht, der nicht gezeichnet wird - er ist nur ein zwischenstueck.

Die layers dienen dazu, den fill path unter die anderen zu packen.

Permanenter link

beantwortet 01 Apr '14, 14:58

cfeuersaenger's gravatar image

cfeuersaenger
97723

bearbeitet 02 Apr '14, 14:45

@cfeuersaenger Gut zu wissen, dass die fillbetween Bibliothek auch einfach mit TikZ verwendet werden kann. Vielen Dank für die Erklärungen dazu. Schon deshalb hat sich das Fragestellen hier gelohnt :-)

(02 Apr '14, 03:42) esdd

Dem kann ich nur zustimmen, mir war das auch neu!

(02 Apr '14, 04:02) stefan ♦♦

@esdd Freut mich. Die fillbetween bibliothek arbeitet tatsaechlich relativ low-level und man kann sie recht vielseitig einsetzen. Richtig gut klappt sie bei "funktionsartigen" Pfaden (d.h. Pfade, die sich nicht selber schneiden oder andere Schweinereien machen); bei generellen Pfaden kann die aber auch mal in die Knie gehen, glaube ich.

(02 Apr '14, 14:47) cfeuersaenger

Eine Möglichkeit ist die Nutzung von \clip um die Schnittfläche zu ermitteln.

  • Die Pfade werden als Befehle definiert, da ich sie jeweils zwei Mal benutze.
  • Beim Zeichnen der drei Pfade werden zwei Eckpunkte der gemeinsamen Bounding Box dieser Kurven als Koordinaten gespeichert.
  • Mit Hilfe der beiden gespeicherten Punkte und der drei Pfade wird die Schnittfläche der Kurven ausgeschnitten und gefüllt.
  • Damit die Kurven trotz Füllung vollständig sichtbar bleiben, erfolgt das Ermitteln und Füllen der Schnittfläche im Hintergrund.
Open in writeLaTeX
\documentclass[tikz, margin=5mm]{standalone} 
\usetikzlibrary{backgrounds}
\begin{document} 
\begin{tikzpicture}
% Definition der Kurven
  \def\KurveI{(2,5) .. controls (6,5) .. (10,1)}
  \def\KurveII{(1,1) .. controls (3,4) .. (10,5)}
  \def\KurveIII
      {(1,2) .. controls (3,3) and (7,0) .. (9,2) ..controls (10,3.5) .. (10,3.5)}
% Zeichnen der Kurven, Ermitteln von deren gemeinsamer Bounding Box
  \draw \KurveI \KurveII \KurveIII 
    (current path bounding box.south west)coordinate(UL)
    (current path bounding box.north east)coordinate(OR);
  \begin{scope}[on background layer]
    \clip (UL)--\KurveI--(UL-|OR)--cycle;% Fläche unterhalb der 1.Kurve
    \clip (UL-|OR)--\KurveII--(OR)--cycle;% Fläche rechts von 2.Kurve
    \clip (UL|-OR)--\KurveIII--(OR)--cycle;% Fläche oberhalb von 3.Kurve
    \fill[yellow!50](UL)rectangle(OR);% Füllen der Schnittfläche
  \end{scope}
\end{tikzpicture} 
\end{document}

alt text


Theoretisch könnte man sich auch ein Makro definieren, dass drei Kurven zeichnet und deren Schnittfläche füllt. Allerdings muss bei der Angabe der Pfade dann die Reihenfolge und die Richtung so gewählt werden, dass sich die Schnittfläche aus der Fläche unterhalb des ersten Pfades, rechts des zweiten und oberhalb des dritten Pfades ergibt.

Open in writeLaTeX
\documentclass{standalone} 
\usepackage{tikz}
\usetikzlibrary{backgrounds}

\newcommand\DreiKurven[4][lightgray]{%
  \draw #2 #3 #4 
    (current path bounding box.south west)coordinate(UL)
    (current path bounding box.north east)coordinate(OR);
  \begin{scope}[on background layer]% im Hintergrund
    \clip (UL)--#2--(UL-|OR)--cycle;% Fläche unterhalb der 1.Kurve
    \clip (UL-|OR)--#3--(OR)--cycle;% Fläche rechts von 2.Kurve
    \clip (UL|-OR)--#4--(OR)--cycle;% Fläche oberhalb von 3.Kurve
    \fill[#1](UL)rectangle(OR);% Füllen der Schnittfläche
  \end{scope}
  }

\begin{document} 
\begin{tikzpicture} 
\DreiKurven[yellow!50]
  {(2,5) .. controls (6,5) .. (10,1)}
  {(1,1) .. controls (3,4) .. (10,5)}
  {(1,2) .. controls (3,3) and (7,0) .. (9,2) ..controls (10,3.5) .. (10,3.5)}
\end{tikzpicture} 
\end{document}
Permanenter link

beantwortet 01 Apr '14, 12:15

esdd's gravatar image

esdd
14.2k53251

bearbeitet 01 Apr '14, 12:30

@esdd Sehr gute Lösung und prima Erklärung! Solche Beiträge sind eine schöne Einladung für mögliche neue Nutzer auf TeXwelt.de, daher freue ich mich besonders.

(01 Apr '14, 12:35) stefan ♦♦

Hier ist die dazu passende Lösung mit Asymptote:

Open in writeLaTeX
fill(buildcycle(curveI,reverse(curveIII),curveII),yellow);

( http://www.artofproblemsolving.com/Forum/viewtopic.php?f=519&t=583634&p=3450494#p3450494 )

Open in writeLaTeX
texpreamble("\usepackage[pdfpagemode=FullScreen,
  pdftitle={Filling area bounded in several Subpaths},
  pdfsubject={Asymptote-Programmierung},
  pdfauthor={Klaus Heidrich Goettingen 2014},
  pdfkeywords={Asymptote, Vektor-Grafik, LaTeX}
]{hyperref}
");

//import settings;
//pdfviewer="evince"; // for Linux
//batchView=true;
//outformat="pdf";

unitsize(1cm);
fill(box((0,0),(11,5.8)),white);
pair A1=(2,5),A2=(10,1);
pair B1=(1,1),B2=(10,5);
pair C1=(1,2),C2=(10,3.5);
path curveI = A1 .. controls (6,5) .. A2;
path curveII = B1 .. controls (3,4) .. B2;
path curveIII = C1 .. controls (3,3) and (7,0) .. (9,2) ..controls C2 .. C2;
fill(buildcycle(curveI,reverse(curveIII),curveII),yellow);
draw(curveI, red);
draw(curveII, blue);
draw(curveIII, green);
pair ip_1 = intersectionpoint(curveI, curveII);
pair ip_2 = intersectionpoint(curveII, curveIII);
pair ip_3 = intersectionpoint(curveI, curveIII);
label("$A_1$",A1,1.5W, red);
label("$A_2$",A2,1SE, red);
label("$B_1$",B1,1.5SSW, heavyblue);
label("$B_2$",B2,1.12E, heavyblue);
label("$C_1$",C1,1.5W, heavygreen);
label("$C_2$",C2,1.25E, heavygreen);
dot(ip_1^^ip_2^^ip_3);
label("$S_1$",ip_1, 1.5*NNE);
label("$S_2$",ip_2, 1.5*SSE);
label("$S_3$",ip_3, 1.85*dir(-93));
dot(A1^^A2, mediumred);
dot(B1^^B2, mediumblue);
dot(C1^^C2, mediumgreen);
draw(ip_1^^ip_2^^ip_3^^A1^^A2^^B1^^B2^^C1^^C2, white);
settings.render=2.4;
//shipout(bbox(.3cm, white),format="pdf");
shipout(bbox(white+linewidth(10)+linejoin(0)),format="png");

Die von TeX und Asymptote erzeugte pdf-Datei habe ich mit gimp eingelesen und dann von da aus als jpg-Rastergrafik abgespeichert.

Bearbeitungsnotiz: Den obigen Code habe ich verbessert. Den Hintergrund habe ich für die Rastergrafik vor dem eigentlichen Zeichnen zuerst mit weiß gefüllt und zudem einen render-Wert angegeben. Hier nun ist die von Asymptote selbst mit ImageMagick automatisch erzeugte Rastergrafik.

Und hier also jetzt das gewünschte Bild in viel besserer Qualität.

Permanenter link

beantwortet 02 Apr '14, 13:58

Klaus%20Heidrich's gravatar image

Klaus Heidrich
5215

bearbeitet 03 Apr '14, 10:55

1

Prima, auch ich bin interessiert an alternativen Lösungen! Insbesondere an Asymptote, was ich auch lernen möchte. Neben TikZ Galerie und PGFPlots Sammlung starte ich bei Interesse gern eine Asymptote Galerie - an Beispielen lernt man ja am besten. Quellen kenne ich, nur keine deutschsprachigen. Da an TeXwelt mein Herz hängt, bin ich motiviert, sobald hier was passiert ;-) z.B. informative Archiv-Posts. asymptote.info schonmal vorbereitet und erstmal mit feed belegt.

(02 Apr '14, 15:08) stefan ♦♦
1

@Klaus Heidrich Danke für den kompletten Code. Ich hab ihn einschließlich des Bildes in diese Antwort hier eingefügt.

Einen Codeblock kannst du hier formatieren, in dem du ihn nach der Eingabe markierst und danach entweder Ctrl+K oder den Codebutton verwendest. Oder du rückst schon beim Eingeben jede Zeile um 4 Leerzeichen ein.

(02 Apr '14, 17:40) esdd
Deine Antwort auf die Frage (nicht auf andere Antworten)
Knebel-Vorschau

Folge dieser Frage

Per E-Mail:

Wenn Du Dich anmeldest, kannst Du Updates hier abonnieren

Per RSS:

Antworten

Antworten und Kommentare

Aktuelle Buch-Infos

LaTeX Cookbook

LaTeX Beginners Guide

Limitierter Rabatt ebook
50% Coupon code tDRet6Y

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üge einfach zwei Leerzeichen an die Stelle ein, an der die neue Zeile sein soll.
  • grundlegende HTML-Tags werden ebenfalls unterstützt

Zugeordnete Themen:

×492
×160
×108
×6

Frage gestellt: 01 Apr '14, 11:42

Frage wurde angeschaut: 4,970 Mal

Zuletzt aktualisiert: 03 Apr '14, 10:55