4

I am trying to create angled lines from a point to specific border. Here is a minimal example:

\documentclass[margin=2mm]{standalone} 
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
    \coordinate (A) at (0, 0);
    \coordinate (B) at (5, 0);
    \coordinate (C) at (5, -5);
    \coordinate (D) at (1, -4);
    \clip (A) rectangle (C); 
    \draw (A) -- (B) -- (C);
    \foreach \a in {10,30,...,70}{
        \draw (D) -- +(\a:3);
    }
\end{tikzpicture}
\end{document}

How do I set the length of these lines? 3 is to short. Setting the value to 10 solves the problem. However, resizing A, B and C gives the same problem. Is it possible to draw the lines until they hit a border? Or can I calculate a length in TikZ? I only know the calculation of points, but here I need a length.

Dirk
  • 2,728

3 Answers3

5

Here a suggestion where you compute the maximum distance between coordinates.

The function \MaxNodeDistance has two mandatory arguments. The first argument is the reference point. The second argument can be a list with defined coordinates. The result of the function is the macro \Distance.

The command \gettikxy is taken from https://tex.stackexchange.com/a/33765/5239

To demonstrate the command I change the command clip to draw and add the angle 45 which is the maximum distance.

\documentclass[margin=2mm]{standalone} 
\usepackage{tikz}
\usepackage{xparse}
\ExplSyntaxOn
\makeatletter
\newcommand{\gettikzxy}[3]{%
  \tikz@scan@one@point\pgfutil@firstofone#1\relax
  \edef#2{\the\pgf@x}%
  \edef#3{\the\pgf@y}%
}
\makeatother
\NewDocumentCommand \MaxNodeDistance { m >{ \SplitList { , } } m }
 {
  \def\Distance{0pt}
  \gettikzxy{(#1)}{\xa}{\ya}
  \ProcessList {#2} { \dirk_nodedistance_aux:n }
%  \Distance
 }
\cs_new:Npn  \dirk_nodedistance_aux:n #1
 {
    \gettikzxy{(#1)}{\xb}{\yb}
    \pgfmathparse{max( (veclen(\xa-\xb,\ya-\yb)) ,\Distance }
    \edef\Distance{\pgfmathresult pt}
 }
\ExplSyntaxOff

\begin{document}
\begin{tikzpicture}
    \coordinate (A) at (0, 0);
    \coordinate (B) at (5, 0);
    \coordinate (C) at (5, -5);
    \coordinate (D) at (1, -4);
    \draw (A) rectangle (C); 
    \MaxNodeDistance{D}{A,B,C} 
    \draw (A) -- (B) -- (C);
    \foreach \a in {10,30,45,50,70,90}{
        \draw (D) -- +(\a:\Distance);
    }
\end{tikzpicture}
\end{document}

enter image description here

Marco Daniel
  • 95,681
  • Thank you! However, it is much code to get a length. I was wondering, that it is so difficult to calculate this length. I took your proposed veclen and create another solution. I post it in this thread. – Dirk Jun 05 '13 at 14:28
4

First solution, instead of 3cm use a larger length, 10cm. Your clip rectangle will cut all lines at its border.

\documentclass[margin=2mm]{standalone} 
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
    \coordinate (A) at (0, 0);
    \coordinate (B) at (5, 0);
    \coordinate (C) at (5, -5);
    \coordinate (D) at (1, -4);
    \clip (A) rectangle (C); 
    \draw (A) -- (B) -- (C);
    \foreach \a in {10,30,...,70}{
        \draw (D) -- +(\a:10);
    }
\end{tikzpicture}
\end{document}

Second solution: use intersections library:

1- Load library:

\usetikzlibrary{intersections}

2- Define which paths will be intersected assigning a name to them:

\draw[name path=border] (A) -- (B) -- (C);

\path[name path=line] (D)--+(\a:10);

3- draw the angled line form its origin to intersection point:

\draw[name intersections={of=border and line}] (D) -- (intersection-1);

With this solution you don't need to use a clip path but if you need a bounding box which not considers (\a:10) points must use overlay option in:

\path[name path=line,overlay] (D)--+(\a:10);

The complete code is:

\documentclass[margin=2mm]{standalone} 
\usepackage{tikz}
\usetikzlibrary{intersections}
\begin{tikzpicture}
    \coordinate (A) at (0, 0);
    \coordinate (B) at (5, 0);
    \coordinate (C) at (5, -5);
    \coordinate (D) at (1, -4);
 %   \clip (A) rectangle (C); 
    \draw[name path=border] (A) -- (B) -- (C);
    \foreach \a in {10,30,...,70}{
        \path[name path=line,overlay] (D)--+(\a:10);
        \draw[name intersections={of=border and line}] (D) -- (intersection-1);
    }
\end{tikzpicture}
\end{document}

Both solutions will give you

enter image description here

Ignasi
  • 136,588
  • Your second approach needs also a manual set of the length. – Marco Daniel Jun 05 '13 at 13:53
  • @MarcoDaniel: Yes, it needs. Dirk's code draws lines which don't reach the border, so I thought the problem was how to reach the border without drawing beyond it. – Ignasi Jun 05 '13 at 14:15
  • I said, that it should work with different coordinates, so I do not knwo a suitable maximum length. – Dirk Jun 05 '13 at 14:26
  • @Dirk: In your example you are using a fixed length. – Marco Daniel Jun 05 '13 at 14:30
  • Yes, but I wrote that this does not solve my problem. I mentioned, that I can set the value to 10, but this does not solve the problem, too. – Dirk Jun 05 '13 at 15:59
  • Intersecting the lines is an interessting way, but one needs a value (here it is 10) that intersects the border. Usually, this is not given when adjusting A, B, C. – Dirk Jun 06 '13 at 09:30
  • @Dirk: I used 10 (means 10cm) because it was long enough. I imagin that you have a certain idea about your diagram's final size and can provide a number large enough. If not, just use an exagerated number (583 was the larger which worked for me). It won't have any effect over your diagram if you use clip or use intersections to delimit the graphic. Of course it's not so elegant and clever as Marco's solution, but it's easier to remember. – Ignasi Jun 07 '13 at 09:00
  • You are right. However, I do not want to restrict me to a certain number. So I use length like \textwidth and \textheight in my solution. – Dirk Jun 07 '13 at 15:48
1

I took this solution:

\documentclass[margin=2mm]{standalone} 
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}
    \coordinate (A) at (0cm, 0cm);
    \coordinate (B) at (5cm, 0cm);
    \coordinate (C) at (5cm, -5cm);
    \coordinate (D) at (1cm, -4cm);

    \newlength\lendiag;
    \pgfmathsetlength{\lendiag}{veclen(\linewidth,\linewidth)};

    \clip (A) rectangle (C); 


    \draw (A) -- (B) -- (C);

    \foreach \a in {10,30,...,70}{
        \draw (D) -- +(\a:(\lendiag););
    }
\end{tikzpicture}

\end{document}

In this minimal example, I took \linewidth twice which is independend of the given points. This is not optimal, of cause. In my productive solution I use \textwidth and \textheight to determine the points and to calculate \lendiag. So the length is always long enough.

Dirk
  • 2,728