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, 17:42

esdd's gravatar image

esdd
17.8k284257
Akzeptiert-Rate: 62%

bearbeitet 02 Apr '14, 21:08

stefan's gravatar image

stefan ♦♦
18.3k163148

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, 17:42) esdd

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

(01 Apr '14, 18: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, 20:58

cfeuersaenger's gravatar image

cfeuersaenger
3.7k23
Akzeptiert-Rate: 34%

bearbeitet 02 Apr '14, 20: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, 09:42) esdd

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

(02 Apr '14, 10: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, 20: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, 18:15

esdd's gravatar image

esdd
17.8k284257
Akzeptiert-Rate: 62%

bearbeitet 01 Apr '14, 18: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, 18: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, 19:58

Klaus%20Heidrich's gravatar image

Klaus Heidrich
52125
Akzeptiert-Rate: 0%

bearbeitet 03 Apr '14, 16: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, 21: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, 23:40) esdd
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:

×731
×298
×117
×7

gestellte Frage: 01 Apr '14, 17:42

Frage wurde gesehen: 19,905 Mal

zuletzt geändert: 03 Apr '14, 16:55