如何保存和恢复 tikzpictures 之间的节点?

如何保存和恢复 tikzpictures 之间的节点?

我的英语不够好,所以如果问题太长,请原谅我

下一个代码不是很有趣,但它可以正确说明我的问题。

我有很多宏,实际上我需要很多临时节点。到目前为止,我尝试使用不同的名称,但这些名称太多了。现在我尝试对临时节点使用相同的名称,但我得到了一些副作用。

A] 示例 1下一个代码显示节点未在环境“tikzpicture”本地定义。问题是节点继续存在于 tikzpicture 环境之间。我想有充分的理由...

当同一个文件上有多个环境时,请确保所有点仅在新环境中定义,而不是在最后一个环境中定义。

\documentclass{article}
\usepackage{tikz} 

\begin{document}

\begin{tikzpicture}
\coordinate (a) at (1,2);
\coordinate (b) at (1,3);
\coordinate (c) at (1,4);
% save 
\end{tikzpicture}

\begin{tikzpicture}
  \foreach \c in {a,...,c}{ \fill[red] (\c) circle (1.5 pt); }
\end{tikzpicture}

\begin{tikzpicture}
\coordinate (a) at (2,2);
\coordinate (b) at (2,3);
\coordinate (c) at (2,4);
 \foreach \c in {a,...,c}{ \fill[blue] (\c) circle (1.5 pt); }
\end{tikzpicture}

%restore I would like to use the same nodes like at the beginning
\begin{tikzpicture}
  \foreach \c in {a,...,c}{ \fill[red] (\c) circle (1.5 pt); } % with 
\end{tikzpicture}
\end{document}

有可能用以下方法擦除两个“tikzpictures”之间的所有点

\begin{tikzpicture}
    \foreach \p in {a,b,c,pta,ptb,ptc}{\pgfnoderename{}{\p}}
    % \draw (a) -- (b) ;
    % Latex Error: ./nested_cs.tex:59 Package pgf Error: No shape named a is known.
\end{tikzpicture}

乙] 示例 2对我来说,这是主要问题。使用宏或控制序列。关于下一个代码的一些解释。\tr``\drawpoints并且\labelpoints仅用于控制结果

三个宏

  • 第一个\subone在这里取三个点ab然后c在这里找到一些中点ptaptb然后ptc

  • 然后\subtwo也使用ptaptbptc想限制临时点的数量

  • 并且\main此宏使用最后两个宏\subone\subtwo。由于\subtwo我输了ptaptb并且ptc在中定义\subone

两个宏之间的问题是:我需要在宏中使用 pta、ptb 和 ptc 来定义一个对象,而这个宏调用另一个也使用 pta、ptb 和 ptc 的宏。会产生一些副作用...我认为用节点名称来解决这个问题很困难,但也许可以用等方法解决\pta\ptb

我的问题就是找到一种方法来保存第一个ptaptbptc在最后一个恢复它们\subtwo

  \documentclass{article}
  \usepackage{tikz} 
  \usetikzlibrary{quotes}
  %-------------------------------------------------------------
  \def\tr[#1](#2,#3,#4){\draw[#1] (#2) -- (#3) -- (#4) --cycle;}
  \def\drawpoints(#1){%
    \foreach \pt in {#1} {\fill (\pt) circle (2 pt);}}
  \def\labelpoints(#1){%
    \foreach \pt in {#1} {\path  coordinate["\pt" below] () at (\pt) ;}}
   %-------------------------------------------------------------           
   \def\subone(#1,#2,#3){% the macro defines midpoints of #1#2 #1#3 and #2#3
     \path[coordinate](barycentric cs:#1=1,#2=1) coordinate (ptc);
     \path[coordinate](barycentric cs:#1=1,#3=1) coordinate (ptb);
     \path[coordinate](barycentric cs:#2=1,#3=1) coordinate (pta);
      }
   %-------------------------------------------------------------
   \def\subtwo(#1,#2,#3){% the macro defines the centroid of (#1,#2,#3)
    % then some symetric points and the last one result
     \path[coordinate](barycentric cs:#1=1,#2=1,#3=1)coordinate (ptd);
     \path[coordinate](barycentric cs:#1=1,ptd=-2)       coordinate (pta);
     \path[coordinate](barycentric cs:#2=1,ptd=-2)       coordinate (ptb);
     \path[coordinate](barycentric cs:#3=1,ptd=-2)       coordinate (ptc);
     \path[coordinate](barycentric cs:pta=1,ptb=1,ptc=-1) coordinate (result);  
}
 %-------------------------------------------------------------
 \def\main(#1,#2,#3){%
    \subone(#1,#2,#3) % call to the first macro
    \subtwo(pta,ptb,ptc) % subtwo affects the values of pta,... etc.
    \draw (result) -- (pta) (result) -- (ptb) (result) -- (ptc);
 }
 \begin{document}
    \begin{tikzpicture}
    \path    coordinate (a) at (0,1)
             coordinate (b) at (5,2)
             coordinate (c) at (1,6);
     \tr[red](a,b,c)
     \subone(a,b,c)
     \drawpoints(a,b,c)
     \drawpoints(pta,pt...,ptc) % this is a test midpoints are defined
     \labelpoints(pta,pt...,ptc)

    %     \subtwo(a,b,c) % test subtwo is correct
    % \drawpoints(pta,pt...,ptd,result)
    % \labelpoints(pta,pt...,ptd,result)
    % \tr[blue](pta,ptb,ptc)

    \main(a,b,c)
    \drawpoints(pta,pt...,ptc)
    \tr[green](pta,ptb,ptc)
    \labelpoints(pta,pt...,ptd,result) 
    \end{tikzpicture}

 \end{document}

C]研究

我尝试了不同的方法。第一个想法是使用 tikz/pgf 中的工具,如 \pgfnodealias和,pgfnoderename但这些宏似乎
无效。

指向\pgfnodealias{n_pta}{pta} n_pta但是ptapta重新定义时则n_pta指向新值所以我丢失了旧值。

\pgfnoderename{n_pta}{pta} n_pta替换“pta”则这个丢失了!

下一个想法:我尝试使用宏来存储坐标。我认为这是解决方案,但我错过了一些东西……例如,下一个代码(我不确定它是否正确)可以保存坐标

\makeatletter
\newdimen\pt@xa
\newdimen\pt@ya
\def\SavedCoordPoint#1#2{%
    \pgfextractx{\pt@xa}{\pgfpointanchor{#2}{center}}%
    \pgfextracty{\pt@ya}{\pgfpointanchor{#2}{center}}%
    \pgfextract@process\tkzsavepoint{\pgfpoint{\pt@xa}{\pt@ya}}%
    \global\expandafter\edef\csname #1\endcsname{\tkzsavepoint}% 
}
\makeatother
% ex \SavedCoordPoint{pta}{pta}

也许这个代码可以重写,但想法是将的坐标保存pta 到宏中\pta。现在我需要重写所有代码,因为我需要使用宏而不是节点的名称。

\pgf@process也许另一个宏对于恢复坐标有用 。

D]具体例子

为了得到三角形 ABC 的欧拉中心,我需要

1)获取(A,B,C)的 CentroidTriangle,其\tkzDefCentroidTriangle(A,B,C){tkz@pta,tkz@ptb,tkz@ptc} {tkz@pta,tkz@ptb,tkz@ptc}是每个线段的中点。

2)然后我需要得到{tkz@pta,tkz@ptb,tkz@ptc} \tkzCircumCenter(tkz@pta,tkz@ptb,tkz@ptc)

3)为了得到外心,我需要得到一些中介线……等等

每次调用时我都需要使用临时点。如果我使用不同的名称(节点),则不会出现问题,但如果我更改了名称,代码就会失败。在每个宏的开头,一个好主意是保存{tkz@pta,tkz@ptb,tkz@ptc}它们,然后使用它们,然后在退出之前恢复它们。但是该怎么做呢?

答案1

如果我理解正确的话,你想使用相对的保存的节点在新图片中的位置。也就是说,每个节点都应引用新图片中相对于新原点的位置。

以下是一些代码,用于保存指定节点列表的所有数据,然后稍后可以在文档中恢复这些数据。它在内部使用 LaTeX3 的东西,因为它更多的是关于编程和扩展,而 L3 可以做到这一点所以容易多了。

\documentclass{article}
%\url{http://tex.stackexchange.com/q/307356/86}
\usepackage{tikz} 
\usepackage{xparse}

\ExplSyntaxOn

% We save our information in a ``property list'', which is L3's
% version of an associative array or dictionary.  They keys will give
% the ability to store several groups of nodes and restore them at
% will.
\prop_new:N \g__sn_prop
% We'll need a token list for constructing the saved data.
\tl_new:N \l__sn_tmpa_tl

% This is the command that actually does the work.  It constructs a
% token list which contains the code that will restore the node data
% when invoked.  The two arguments are the name of this group (for
% reference later) and a comma separated list of the node names to be
% saved.
\cs_new_nopar:Npn \save_nodes:nn #1#2
{
  % Clear our token list
  \tl_clear:N \l__sn_tmpa_tl
  % Iterate over the list of node names
  \clist_map_inline:nn {#2}
  {
    % Before we start trying to save the node, check that it exists.
    % The macro \pgf@sh@ns@nodename is only defined if that node exists.
    \tl_if_exist:cT {pgf@sh@ns@##1}
    {
      % The node information is stored in a series of macros of the form
      % \pgf@sh@XX@nodename where XX is one of the following.
      \clist_map_inline:nn {ns,np,ma,nt,pi}
      {
        % Our token list will look like:
        %
        % \tl_set:cn {pgf@sh@XX@nodename} {<current contents of that macro>}
        %
        % This will restore \pgf@sh@XX@nodename to its current value
        % when this list is invoked.
        %
        % This part puts the \tl_set:cn {pgf@sh@XX@nodename} in place
        \tl_put_right:Nn \l__sn_tmpa_tl
        {
          \tl_set:cn {pgf@sh@####1@##1}
        }
        % Now we put the current contents in place.  We're doing this in
        % an expansive context to get at the contents.  The \exp_not:v
        % part takes the current value of \pgf@sh@XX@nodename and puts
        % it in place, preventing further expansion.
        \tl_put_right:Nx \l__sn_tmpa_tl {{\exp_not:v {pgf@sh@####1@##1}}}
      }
    }
  }
  % Once we've assembled our token list, we store it in the property
  % list using the key we were given.
  \prop_gput:NnV \g__sn_prop {#1} \l__sn_tmpa_tl
}

\cs_new_nopar:Npn \restore_nodes:n #1
{
  % Restoring nodes is simple: look in the property list for the key
  % and if it exists, invoke the macro stored there.
  \prop_get:NnNT \g__sn_prop {#1} \l__sn_tmpa_tl
  {
    \tl_use:N \l__sn_tmpa_tl
  }
}

% These two are wrappers around our internal commands.
%
% The first argument is the label for our group of nodes (so that we
% can refer to them later) and the second argument is a comma
% separated list of nodes to save.
\DeclareDocumentCommand \SaveNodes {m m}
{
  \save_nodes:nn {#1}{#2}
}

% The argument to this is the label for our group of nodes to restore.
\DeclareDocumentCommand \RestoreNodes {m}
{
  \restore_nodes:n {#1}
}

\ExplSyntaxOff

\begin{document}

\begin{tikzpicture}
\coordinate (a) at (1,2);
\coordinate (b) at (1,3);
\coordinate (c) at (1,4);
% save
\SaveNodes{here}{a,b,c}
\end{tikzpicture}

\begin{tikzpicture}
\fill[black] (0,0) circle (1.5 pt);
  \foreach \c in {a,...,c}{ \fill[red] (\c) circle (1.5 pt); }
\end{tikzpicture}

\begin{tikzpicture}
\coordinate (a) at (2,2);
\coordinate (b) at (2,3);
\coordinate (c) at (2,4);
\fill[black] (0,0) circle (1.5 pt);
 \foreach \c in {a,...,c}{ \fill[blue] (\c) circle (1.5 pt); }
\end{tikzpicture}

%restore I would like to use the same nodes like at the beginning
\begin{tikzpicture}
\RestoreNodes{here}
\fill[black] (0,0) circle (1.5 pt);
  \foreach \c in {a,...,c}{ \fill[red] (\c) circle (1.5 pt); } % with 
\end{tikzpicture}
\end{document}

我在原点添加了黑色圆圈,以表明使用的是原始节点,而不是新节点。我思考我保存了有关节点的所有信息,而不仅仅是它们的坐标,因此此解决方案适用于一般节点,而不仅仅是坐标。再多做一点工作,就可以在恢复阶段获取节点列表并仅恢复这些节点。

已保存节点位置

这是非 L3 版本。它以每个节点为基础工作(但如果节点始终具有相同的名称,则您可能可以将其包装起来)。

\makeatletter

\def\@savecoord#1#2{%
  \expandafter\let\expandafter\sn@temp\csname pgf@sh@#1@#2\endcsname
  \expandafter\def\expandafter\sn@tempb\expandafter{%
    \expandafter\gdef\csname pgf@sh@#1@#2\expandafter\endcsname\expandafter{%
      \sn@temp
    }%
  }%
  \expandafter\g@addto@macro\expandafter\sn@tempa\expandafter{\sn@tempb}%
}

% {ns,np,ma,nt,pi}
\def\savecoordinate#1#2{%
  \def\sn@tempa{}%
  %
  \@savecoord{ns}{#2}%
  \@savecoord{np}{#2}%
  \@savecoord{ma}{#2}%
  \@savecoord{nt}{#2}%
  \@savecoord{pi}{#2}%
%
  \expandafter\global\expandafter\let\csname sn@#1\endcsname\sn@tempa
}

\def\restorecoordinate#1{%
  \csname sn@#1\endcsname
}

\makeatother

答案2

另一种方法是创建一个包含宏节点的堆栈。每次调用宏都会在堆栈中创建新级别,并在宏结束时删除该级别。可以通过挑选节点来保留所选节点,并且只保留对未来有用的节点。

在宏的开头声明一些节点(人类可读的名称),它们将充当本地节点:它们不会覆盖现有节点并在宏的末尾消失。声明顺序必须与输出列表顺序相同。

因此多次调用宏不会造成混淆或丢失。

所有节点都在一个宏中计算,绘图是可选的:

\CercleEuler[o,I,J,K,P1,P2,P3,J1,J2,J3,G,H,O]{%
     a,b,c}<fill=lightgray!20,draw=gray,semithick>

在此处输入图片描述

\documentclass{article}
\usepackage{tikz,xparse} 
\usetikzlibrary{quotes,through,calc}

\ExplSyntaxOn
\NewDocumentCommand{\ExtractFromList}{%
    m % macro
    m % list
    m % number : -1 for the last 
    }
 {
  \tl_set:Nx #1 {\clist_item:Nn #2 { #3 } }
 }

\NewDocumentCommand{\NewPoints}{m}
 {
  \clist_map_inline:nn { #1 }
   {
    \cs_set:cpx { ##1 } { a-\NumNode-\theLittNode }
    \stepcounter{LittNode}
   }
 }
\ExplSyntaxOff

% counter for naming nodes
\newcounter{LittNode}

% level of calling
\pgfmathtruncatemacro{\NumNode}{0}

% node named #1 at the current level
\def\N#1{a-\NumNode-#1}

\makeatletter % ------------------------ #### Make @ Letter

% -------------------------------------- #### AtBeginTikzMacro
\newcommand{\AtBeginTikzMacro}[1]{%
    \pgfmathtruncatemacro{\NumNode}{\NumNode+1}
    \expandafter\edef\csname OutPut-\NumNode\endcsname{#1}
    \setcounter{LittNode}{1}
    \begingroup % au début de chaque macro
}

% -------------------------------------- #### KeepUsefullNodes
\newcommand{\KeepUsefullNodes}{%
    \endgroup   % à la fin de chaque macro
    \edef\Sortie{\csname OutPut-\NumNode \endcsname}
    \foreach \Nd [count=\i from 1]
        in \Sortie {%
        \coordinate (\Nd) at (\N{\i}) ;
    }
    \pgfmathtruncatemacro{\NumNode}{\NumNode-1}
}

%-----------------------------------------------------------
\def\tr[#1](#2,#3,#4){\draw[#1] (#2) -- (#3) -- (#4) --cycle;}
\def\drawpoints(#1){%
\foreach \pt in {#1} {\fill (\pt) circle (2 pt);}}
\def\labelpoints(#1){%
\foreach \pt in {#1} {\path  coordinate["\pt" below] () at (\pt) ;}}
%-----------------------------------------------------------

% #### --------------------------------- #### NodeAngle ####
    % #1 premier point
    % #2 second point
    % On récupère le résultat dans \MyAngle
\newcommand{\NodeAngle}[3][\MyAngle]{%
    \pgfextra{
        \pgfmathanglebetweenpoints%
            {\pgfpointanchor{#2}{center}}%
            {\pgfpointanchor{#3}{center}}%
            \global\let#1\pgfmathresult
    }}

% #### --------------------------------- #### NodeDist ####
    % #1 premier point
    % #2 second point
    % On récupère le résultat dans \MyDist
\newcommand{\NodeDist}[3][\MyDist]{%
    \pgfpointdiff{\pgfpointanchor{#2}{center}}
                 {\pgfpointanchor{#3}{center}}
    % no need to use a new dimen
    \pgf@xa=\pgf@x
    \pgf@ya=\pgf@y
    % to convert from pt to cm   
    \pgfmathparse{veclen(\pgf@xa,\pgf@ya)/28.45274}
    \global\let#1\pgfmathresult % we need a global macro    
}

% #### --------------------------------- #### AngleBAC ####
\newcommand{\AngleBAC}[2][A]{%
    \begingroup

    \edef\List{#2}
    \ExtractFromList\A\List{2}
    \ExtractFromList\B\List{1}
    \ExtractFromList\C\List{3}

    \pgfmathanglebetweenpoints
    {\pgfpointanchor{\A}{center}}
    {\pgfpointanchor{\B}{center}}
    \let\Angl@A\pgfmathresult ;

    \pgfmathanglebetweenpoints
    {\pgfpointanchor{\A}{center}}
    {\pgfpointanchor{\C}{center}}
    \let\Angl@B\pgfmathresult ;

    \pgfmathparse{\Angl@B-\Angl@A}
    \let\Angl@A\pgfmathresult ;
    \expandafter\xdef\csname angle#1\endcsname{\Angl@A}

    \pgfmathparse{cos(\Angl@A)}
    \expandafter\xdef\csname Cos#1\endcsname{\pgfmathresult}
    \pgfmathparse{sin(\Angl@A)}
    \expandafter\xdef\csname Sin#1\endcsname{\pgfmathresult}
    \pgfmathparse{tan(\Angl@A)}
    \expandafter\xdef\csname Tan#1\endcsname{\pgfmathresult}

    \endgroup
}

% #### --------------------------------- #### Milieux ####
\NewDocumentCommand{\Milieux}{%
    s   % * liste de segments, polygone sinon
    O{} % liste de retour
    m   % liste d'entrée
    }{%
    \AtBeginTikzMacro{#2}
    \IfBooleanTF{#1}{%
        % On peut utiliser foreach, mais il ne faut jamais
        % que les noms de variables croisent les noms des nodes
    \foreach \A@/\B@ in {#3} {%
        % On utilise le même nom de macro,
        % mais elle pointe à chaque fois un nouveau nom de node.
        % A la fin on récupère les noms de node
        % pas le nom des macros.
        % On utilisera le même truc à chaque fois que
        % c'est possible.

        % On déclare un node local ou un liste à la fois,
        % sans le \
    \NewPoints{Milieu}
        % Dans une macro, le nom des nodes locaux sont utilisés
        % avec un \ puisque que ce sont des macros
    \coordinate  (\Milieu) at (barycentric cs:\A@=1,\B@=1) ;
        }
    }{%
        \def\List{#3}
        \ExtractFromList\Lastx\List{-1}
        \foreach \x@
            [remember=\x@ as \lastx (initially \Lastx)] in {#3} {%
        \NewPoints{Milieu}
        \coordinate  (\Milieu) at (barycentric cs:\lastx=1,\x@=1) ;
        }
    }
    \KeepUsefullNodes
}

% #### --------------------------------- #### DtEuler ####
\newcommand{\DtEuler}[2][]{%
    \AtBeginTikzMacro{#1}

    \NewPoints{G,H,O}

    \edef\List{#2}
    \ExtractFromList\A\List{1}
    \ExtractFromList\B\List{2}
    \ExtractFromList\C\List{3}

    % Calcul des tangentes
    \AngleBAC[@A]{\B,\A,\C}
    \AngleBAC[@B]{\C,\B,\A}
    \AngleBAC[@C]{\A,\C,\B}

    % isobarycentre
    \coordinate  (\G) at (barycentric cs:\A=1,\B=1,\C=1) ;

    % horthocentre
    \coordinate (\H) at (barycentric
                        cs:\A=\Tan@A,\B=\Tan@B,\C=\Tan@C) ;

    % centre du cercle circonscrit
    \coordinate (\O) at (barycentric
            cs:\A=\Tan@B+\Tan@C,\B=\Tan@A+\Tan@C,\C=\Tan@A+\Tan@B) ;

    \KeepUsefullNodes
}

% #### --------------------------------- #### ProjMAB ####
\NewDocumentCommand{\ProjMAB}{O{}m}{%
    \AtBeginTikzMacro{#1}

    \NewPoints{H}

    \edef\List{#2}
    \ExtractFromList\M\List{1}
    \ExtractFromList\A\List{2}
    \ExtractFromList\B\List{3}

    % Calcul des tangentes
    \AngleBAC[@MAB]{\M,\A,\B}
    \AngleBAC[@MBA]{\A,\B,\M}

    % horthocentre
    \coordinate (\H) at (barycentric
                    cs:\A=\Tan@MAB,\B=\Tan@MBA) ;

    \KeepUsefullNodes
}

\makeatother % ------------------------- #### Make @ Other

% #### --------------------------------- #### ProjABC ####
\NewDocumentCommand{\ProjABC}{O{}m}{%
    \AtBeginTikzMacro{#1}

    \NewPoints{I,J,K}

    \def\List{#2}
    \ExtractFromList\B\List{2}
    \ExtractFromList\C\List{3}

    \ProjMAB[\J]{#2}
    \ProjMAB[\I]{\C,#2}
    \ProjMAB[\K]{\B,\C,#2}

    \KeepUsefullNodes
}

% #### --------------------------------- #### CercleABC ####
\NewDocumentCommand{\CercleABC}{%
    O{} % centre
    m   % A,B,C
    D<>{}   % option pour draw
    }{%

    \AtBeginTikzMacro{#1}

    \NewPoints{O}

    \edef\List{#2}
    \ExtractFromList\A\List{1}
    \ExtractFromList\B\List{2}
    \ExtractFromList\C\List{3}

    \DtEuler[,,\O]{\A,\B,\C}

    \node[circle through=(\A),#3] at (\O) {};

    \KeepUsefullNodes
}

% #### --------------------------------- #### CercleEuler ####
\NewDocumentCommand{\CercleEuler}{%
    O{} % renvoie dans l'ordre:
        % le centre,
        % 3 milieux,
        % 3 projetés,
        % 3 milieux orthocentre-sommet
        % G,H,O
    m   % A,B,C
    D<>{}   % option pour draw
    }{%

    \AtBeginTikzMacro{#1}

    \NewPoints{o,I,J,K,P,Q,R,p,q,r,G,H,O}

    \edef\List{#2}
    \ExtractFromList\A\List{1}
    \ExtractFromList\B\List{2}
    \ExtractFromList\C\List{3}

    \Milieux[\J,\K,\I]{\A,\B,\C}
    \DtEuler[\G,\H,\O]{\A,\B,\C}
    \ProjABC[\R,\P,\Q]{a,b,c}
    \CercleABC[\o]{\I,\J,\K}<#3>
    \Milieux*[\p,\q,\r]{\H/\A,\H/\B,\H/\C}

    \KeepUsefullNodes
}

\tikzset{%
    small dot/.style 2 args={fill=#1,circle,scale=#2},
    small dot/.default={black}{.3},
}

\NewDocumentCommand{\Droite}{%
    O{} % #1 option du path
    m   % #2 premier point sans ()
    m   % #3 second point sans ()
    m   % #4 longueur dans un sens
    m   % #5 longueur dans l'autre
    }{%
        \path[#1] ($(#3)!#4!(#2)$) -- ($(#2)!#5!(#3)$) ;
}

% #1 taille du carré defaut 5pt
% #2 Argument boucle foreach             ---- Angle droit ----
% Point / Angle droit / Point
\NewDocumentCommand{\AngleDt}{
    s       % angle droite simple avec deux points
    D<>{very thin}      % option path
    O{5pt}  % taille du carré
    m       % liste de triplets ou de couples (*)
    }{%
    \IfBooleanTF{#1}{%
    \foreach \B/\A in {#4} {%
        \draw[#2] ($(\B)!#3!(\A)$)
        --($ (\B)!2!($($(\B)!#3!(\A)$)!.5!($(\B)!#3!#190:(\A)$)$)$)
        --($(\B)!#3!#190:(\A)$) ; }
    }{%
    \foreach \A/\B/\C in {#4} {%
        \draw[#2] ($(\B)!#3!(\A)$)
        --($ (\B)!2!($($(\B)!#3!(\A)$)!.5!($(\B)!#3!(\C)$)$) $)
        --($(\B)!#3!(\C)$) ; }
    }
}


\begin{document}

\begin{tikzpicture}[scale=1.1]

\coordinate (a) at (0,1) ;
\coordinate (b) at (7,1) ;
\coordinate (c) at (1,6.4) ;


\CercleEuler[o,I,J,K,P1,P2,P3,J1,J2,J3,G,H,O]{%
    a,b,c}<fill=lightgray!20,draw=gray,semithick>

\tr[black](a,b,c)

\Droite[draw,blue,semithick]{H}{O}{1.6}{1.6}

\Droite[draw,yellow!95!black,semithick,dashed]{I}{O}{1.4}{1.5}
\Droite[draw,yellow!95!black,semithick,dashed]{J}{O}{1.2}{1.2}
\Droite[draw,yellow!95!black,semithick,dashed]{K}{O}{1.2}{1.2}

\draw[draw,red,dashed] (a)--(P1) (b)--(P2) (c)--(P3) ;

\draw[green,dashed] (a)--(I) (b)--(J) (c)--(K) ;

\AngleDt{a/P1/b,b/P2/c,c/P3/a,O/I/c,O/J/a,O/K/b}

\foreach \Coor/\Text/\Pos in 
    {a/$A$/-135,
    b/$B$/-45,
    c/$C$/90,
    I/$I$/20,
    J/$J$/130,
    K/$K$/-50,
    P1/$p_1$/60,
    P2/$p_2$/190,
    P3/$p_3$/-120,
    J1/$j_1$/180,
    J2/$j_2$/-60,
    J3/$j_3$/130,
    G/$G$/-110,
    H/$H$/130,
    O/$O$/-50,
    o/$O'$/130
    } {
    \node[small dot] at (\Coor) {} ;
    \node[shift=(\Pos:8pt),anchor=center] at (\Coor) {\small\Text} ;
    }

\end{tikzpicture}
\end{document}

相关内容