9

Edit (The almost ultimate solution)

After sorting everything out and having some nice code - thanks to cjorssen :) - I cam up with a general solution with which you are able to use the connector with two arbitrary nodes: (The previous code needed the circled node to be at the origin (0,0).

%usage: \arcconnector[color]{Satellite Node}{Circled Node}{rim radius}
\newcommand\arcconnector[4][black]%
{%
    \path [name path=S--C] (#2) -- (#3);
    \path [name path=Rim] (#3.center) circle(#4);
    \path [name intersections={of=S--C and Rim}];
    \pgfmathanglebetweenpoints{%
        \pgfpointanchor{#3}{center}}{%
        \pgfpointanchor{intersection-1}{center}}
    \let\myendresult\pgfmathresult
    \path [draw,color=#1] (intersection-1) arc[start angle=\myendresult,delta angle=-40,x radius=#4,y radius=#4];
    \path [draw,color=#1] (intersection-1) arc[start angle=\myendresult,delta angle=40,x radius=#4,y radius=#4];
    \path [draw,#1] (#2) -- (intersection-1);
}

So for the example depicted below we can do this:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{intersections}
\begin{document}
\begin{tikzpicture}
  \node [shape=circle,draw,minimum size=1cm,red] (C) {};
  \node at (0.8,1.5) [shape=rectangle,draw,blue] (P) {P};
  \arcconnector{P}{C}{0.6cm}
\end{tikzpicture}
\end{document}

Another useful parameter that you may want to adjust is the length of the arc wings (here const 40°).

Edit (after first answer and comments)

I want to draw an arc at an intersection in that way, that the intersection is the middle of the arc. But I don't know how to define \myendresult to be the angle between (Origin intersection-1) and the x-axis.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{intersections}
\begin{document}
\begin{tikzpicture}
  \coordinate (Origin) at (0,0);
  \coordinate (Xaxis) at (1,0);
  % Note: the minimum size is the diameter, so radius = .5cm
  \node [shape=circle,draw,minimum size=1cm,red] (C) {};
  \node at (0.8,1.5) [shape=rectangle,draw,blue] (P) {P};
  \path [name path=P--C] (P) -- (C);
  \path [name path=Rim] (0,0) circle(0.6cm);
  \path [name intersections={of=P--C and Rim}];
  % How to define \myendresult?
  %\path [draw] (intersection-1) arc[start angle=\myendresult,delta
  %  angle=-40,radius=0.6cm]; 
  %\path [draw] (intersection-1) arc[start angle=\myendresult,delta
  %  angle=40,radius=0.6cm]; 
  \path [draw] (P) -- (intersection-1);
\end{tikzpicture}
\end{document}

This should look like the following:

enter image description here

The base problem is to find the correct start angle for arc. Maybe this is also possible by using some tangent calculations?


Original question

The base problem is, that I'd like to compute the angle between two lines given by two coordinates in tikz. That seems to be difficult and because one of the lines is the x-axis (1,0), we can reduce that to:

Calculate the asin from the y-value of the second coordinate (here intersection-1).

But this seems to be a problem. I tried to use \pgfextracty with \pgfmathasin:

\newdimen\myyvalue
\pgfextracty{\myyvalue}{intersection-1}
\node at (1,1) {\myyvalue};
\pgfmathsetmacro{\myendresult}{asin(\myyvalue)}
\path [draw,blue] (intersection-1) arc[start angle=\myendresult,delta angle=30,x radius=0.6cm,y radius=0.6cm];

At line 3 I get "missing number treated as zero". So I tried using the let command:

\path [name intersections={of=A and B},draw,blue] let \p1=(intersection-1) in (intersection-1) arc[start angle=\pgfmathasin{\y1},delta angle=30,x radius=0.6cm,y radius=0.6cm] (intersection-1);

But now I get the error:

! Incomplete \iffalse; all text was ignored after line 821.
<inserted text> 
                \fi

I don't get the errors and am I little bit helpless. It seems no one else ever tried to compute the angle between to vectors/coordinates/points in tikz (at least Google doesn't find anything).

3
  • 2
    Could you post an minimal example with the complete tikzpicture (that is with the definition of nodes A, B, etc.) so that I can adapt my answer specifically to your needs.
    – cjorssen
    Nov 19, 2011 at 21:53
  • I added the example in my question. Unfortunately I'm not allowed to post images therefore I used image paste bin.
    – Hendrik
    Nov 19, 2011 at 23:03
  • 1
    I added the image to your post. A tip: As new user without image posting privileges simply include the image as normal and remove the ! in front of it to turn it into a link. A moderator or another user with edit privileges can then reinsert the ! to turn it into an image again. Nov 19, 2011 at 23:10

1 Answer 1

9

Edit (after you gave a concrete example of what you're were trying to do)

There is no need to define complex macros for what you're after. You can use \pgfmathanglebetweenpoints as in the following example.

\documentclass{standalone}

\usepackage{tikz}

\usetikzlibrary{intersections}

\begin{document}
\begin{tikzpicture}
  \coordinate (Origin) at (0,0);
  \coordinate (Xaxis) at (1,0);
  % Note: the minimum size is the diameter, so radius = .5cm
  \node [shape=circle,draw,minimum size=1cm,red] (C) {};
  \node at (0.8,1.5) [shape=rectangle,draw,blue] (P) {P};
  \path [name path=P--C] (P) -- (C);
  \path [name path=Rim] (0,0) circle(0.6cm);
  \path [name intersections={of=P--C and Rim}];
  % This stores in \pgfmathresult the angle between \vec{Origin
  % intersection-1} and the x-axis
  \pgfmathanglebetweenpoints{%
    \pgfpointanchor{Origin}{center}}{%
    \pgfpointanchor{intersection-1}{center}}
  \let\myendresult\pgfmathresult
  \path [draw] (intersection-1) arc[start angle=\myendresult,delta
    angle=-40,radius=0.6cm]; 
  \path [draw] (intersection-1) arc[start angle=\myendresult,delta
    angle=40,radius=0.6cm]; 
  \path [draw] (P) -- (intersection-1);
\end{tikzpicture}
\end{document}

Original answer

You can give a try to the macros below. You can get the sine, the cosine and the angle with a relatively high accuracy (it uses the fpu library). Note that the mark angle decoration is just here to draw the picture, not for computing the angles. But you will find another way to compute an angle in pgf: \pgfmathanglebetweenpoints (it defines \pgfmathresult to be equal to the angle between the x-axis and the line defined by the two points).

Compute angle

\documentclass{standalone}

\usepackage{tikz}

\usetikzlibrary{calc,fpu,decorations.pathreplacing}

\makeatletter

% Answer to the question
\def\pgfextractxasmacro#1#2{%
  \pgf@process{#2}%
  \edef#1{\the\pgf@x}}
\def\pgfextractyasmacro#1#2{%
  \pgf@process{#2}%
  \edef#1{\the\pgf@y}}
\def\pgfextractxvecasmacro#1#2#3{%
  % #1 macro where the x coor of the \vec{#2#3} is stored
  % #2 node name
  % #3 node name
  \pgfextractxasmacro{#1}{%
    \pgfpointdiff{\pgfpointanchor{#2}{center}}{\pgfpointanchor{#3}{center}}}}
\def\pgfextractyvecasmacro#1#2#3{%
  % #1 macro where the x coor of the \vec{#2#3} is stored
  % #2 node name
  % #3 node name
  \pgfextractyasmacro{#1}{%
    \pgfpointdiff{\pgfpointanchor{#2}{center}}{\pgfpointanchor{#3}{center}}}}

\def\pgfgetsineofAOB#1#2#3#4{%
  % #1 macro where the sine of angle AOB is stored
  % #2 node name A
  % #3 node name O
  % #4 node name B
  \bgroup
  \pgfkeys{/pgf/fpu,pgf/fpu/output format=fixed}
  \pgfextractxvecasmacro{\pgf@xA}{#3}{#2}%
  \pgfextractyvecasmacro{\pgf@yA}{#3}{#2}%
  \pgfextractxvecasmacro{\pgf@xB}{#3}{#4}%
  \pgfextractyvecasmacro{\pgf@yB}{#3}{#4}%
  \pgfmathparse{%
    ((\pgf@xA * \pgf@yB) - (\pgf@xB * \pgf@yA))/(sqrt(\pgf@xA * \pgf@xA
    + \pgf@yA * \pgf@yA) * sqrt(\pgf@xB * \pgf@xB + \pgf@yB * \pgf@yB))}%
  \xdef#1{\pgfmathresult}%
  \egroup\ignorespaces}

\def\pgfgetcosineofAOB#1#2#3#4{%
  % #1 macro where the cosine of angle AOB is stored
  % #2 node name A
  % #3 node name O
  % #4 node name B
  \bgroup
  \pgfkeys{/pgf/fpu,pgf/fpu/output format=fixed}
  \pgfextractxvecasmacro{\pgf@xA}{#3}{#2}%
  \pgfextractyvecasmacro{\pgf@yA}{#3}{#2}%
  \pgfextractxvecasmacro{\pgf@xB}{#3}{#4}%
  \pgfextractyvecasmacro{\pgf@yB}{#3}{#4}%
  \pgfmathparse{%
    ((\pgf@xA * \pgf@xB) + (\pgf@yA * \pgf@yB))/(sqrt(\pgf@xA * \pgf@xA
    + \pgf@yA * \pgf@yA) * sqrt(\pgf@xB * \pgf@xB + \pgf@yB * \pgf@yB))}%
  \xdef#1{\pgfmathresult}%
  \egroup\ignorespaces}

\def\pgfgetangleofAOB#1#2#3#4{%
  % #1 macro where the angle AOB is stored
  % #2 node name A
  % #3 node name O
  % #4 node name B
  \bgroup
  \pgfgetsineofAOB{\pgf@sineAOB}{#2}{#3}{#4}%
  \pgfgetcosineofAOB{\pgf@cosineAOB}{#2}{#3}{#4}%
  \pgfmathparse{atan2(\pgf@cosineAOB,\pgf@sineAOB)}%
  \xdef#1{\pgfmathresult}%
  \egroup\ignorespaces}
% End of the answer
% Begin mark angle decoration
\pgfdeclaredecoration{mark angle}{init}{%
  \state{init}[width = 0pt, next state = check for moveto,
  persistent precomputation = {%
    \xdef\pgf@lib@decorations@numofconsecutivelineto{0}}]{}
  \state{check for moveto}[width = 0pt,
  next state=check for lineto,persistent precomputation={%
    \begingroup
    \pgf@lib@decoraions@installinputsegmentpoints
    \ifx\pgfdecorationpreviousinputsegment\pgfdecorationinputsegmentmoveto
    \gdef\pgf@lib@decorations@numofconsecutivelineto{0}%
    \fi
    \endgroup}]{}
  \state{check for lineto}[width=\pgfdecoratedinputsegmentremainingdistance, 
  next state=check for moveto,persistent precomputation={%
    \begingroup
    \pgf@lib@decoraions@installinputsegmentpoints
    \ifx\pgfdecorationcurrentinputsegment\pgfdecorationinputsegmentlineto
    \xdef\pgf@lib@decorations@numofconsecutivelineto{%
      \number\numexpr\pgf@lib@decorations@numofconsecutivelineto+1\relax}%
    \ifcase\pgf@lib@decorations@numofconsecutivelineto\relax
    \or
    \pgf@process{\pgf@decorate@inputsegment@first}%
    \xdef\pgf@lib@decorations@first@lineto@point{\the\pgf@x,\the\pgf@y}%
    \pgf@process{\pgf@decorate@inputsegment@last}%
    \xdef\pgf@lib@decorations@second@lineto@point{\the\pgf@x,\the\pgf@y}%
    \pgfmathanglebetweenpoints{\pgf@decorate@inputsegment@last}{%
      \pgf@decorate@inputsegment@first}%
    \xdef\pgf@lib@decorations@lineto@startangle{\pgfmathresult}%
    \or
    \pgf@process{\pgf@decorate@inputsegment@last}%
    \xdef\pgf@lib@decorations@third@lineto@point{\the\pgf@x,\the\pgf@y}%
    \pgfmathanglebetweenpoints{\pgf@decorate@inputsegment@first}{%
      \pgf@decorate@inputsegment@last}%
    \xdef\pgf@lib@decorations@lineto@endangle{\pgfmathresult}%
    \pgfdecoratedmarkanglecode
    \fi
    \fi
    \endgroup}]{}
}

\pgfqkeys{/pgf/decoration}{%
  mark angle node text/.store in = \pgfdecoratedmarkanglenodetext,
  mark angle node text = {},
  mark angle code/.store in = \pgfdecoratedmarkanglecode,
  mark angle code = {%
    \fill[red,nearly transparent]
    (\pgf@lib@decorations@second@lineto@point) -- 
    ($(\pgf@lib@decorations@second@lineto@point)!1cm!
    (\pgf@lib@decorations@first@lineto@point)$) 
    arc(\pgf@lib@decorations@lineto@startangle:
    \pgf@lib@decorations@lineto@endangle:1cm) -- cycle;
    \node at ($(\pgf@lib@decorations@second@lineto@point) +
    ({\pgf@lib@decorations@lineto@startangle +
      (\pgf@lib@decorations@lineto@endangle - 
      \pgf@lib@decorations@lineto@startangle)/2}:1.25cm)$)
    {\pgfdecoratedmarkanglenodetext};}} 

\makeatletter

\tikzset{mark angle/.style = {%
    postaction = {%
      decorate,
      decoration = {mark angle}}}}
% End of mark angle decoration
\begin{document}
\begin{tikzpicture}
  \coordinate (O) at (0,0);
  \coordinate (x) at (5,0);
  \coordinate (y) at (0,5);
  \coordinate (M) at (30:5);
  \coordinate (N) at (215:5);
  \pgfgetangleofAOB{\firstangle}{x}{O}{M}%
  \pgfgetangleofAOB{\secondangle}{O}{M}{y}%
  \pgfgetangleofAOB{\thirdangle}{N}{O}{y}%
  \draw[mark angle,/pgf/decoration/mark angle node
    text={$\firstangle$},red] (x) -- (O) -- (M); 
  \draw[mark angle,/pgf/decoration/mark angle node
    text={$\secondangle$},blue] (O) -- (M) -- (y); 
  \draw[mark angle,/pgf/decoration/mark angle node
    text={$\thirdangle$},green] (N) -- (O) -- (y); 
\end{tikzpicture}
\end{document}
6
  • I think calculating the dot product is a more general solution than using the x-axis as a predefined constant (if I understood you correctly).
    – Hendrik
    Nov 19, 2011 at 23:01
  • @Hendrik Yes. But that depends on your needs. It is also possible to generalize without taking the x-axis as a constant using two consecutive \pgfmathanglebetweenpoints and then compute the difference.
    – cjorssen
    Nov 20, 2011 at 10:28
  • Am I missing something? I could not find \pgfmathanglebetweenpoints in the pgf manual. If I had that from the beginning, maybe I wouldn't have sticked with my complex solution. Anyways: Thank you for this really simple solution! And for all the help. Sorry for the trouble I caused.
    – Hendrik
    Nov 20, 2011 at 11:53
  • @Hendrik No trouble at all, don't be sorry! \pgfmathanglebetweenpoints is undocumented... so you didn't miss anything. I guess we should add a short description of it in the manual.
    – cjorssen
    Nov 20, 2011 at 12:20
  • May i suggest you write a book about tikz & gpf? Don't get me wrong, the manual is good, but sometimes I have to search a lot and in different places of the manual to get the whole picture (but maybe its just me).
    – Hendrik
    Nov 20, 2011 at 12:46

You must log in to answer this question.

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