summaryrefslogtreecommitdiff
path: root/graphics/pgf/contrib/liftarm/liftarm.sty
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/pgf/contrib/liftarm/liftarm.sty')
-rw-r--r--graphics/pgf/contrib/liftarm/liftarm.sty1208
1 files changed, 892 insertions, 316 deletions
diff --git a/graphics/pgf/contrib/liftarm/liftarm.sty b/graphics/pgf/contrib/liftarm/liftarm.sty
index b850c8f16a..63d6b51f44 100644
--- a/graphics/pgf/contrib/liftarm/liftarm.sty
+++ b/graphics/pgf/contrib/liftarm/liftarm.sty
@@ -1,12 +1,12 @@
%% liftarm.sty
-%% Copyright 2022 Matthias Floré
+%% Copyright 2022-2024 Matthias Floré
%
% This work may be distributed and/or modified under the
-% conditions of the LaTeX Project Public License, either version 1.3
+% conditions of the LaTeX Project Public License, either version 1.3c
% of this license or (at your option) any later version.
% The latest version of this license is in
% http://www.latex-project.org/lppl.txt
-% and version 1.3 or later is part of all distributions of LaTeX
+% and version 1.3c or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
%
% This work has the LPPL maintenance status `maintained'.
@@ -16,321 +16,897 @@
% This work consists of the files liftarm.pdf, liftarm.sty,
% liftarm.tex and README.md.
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{liftarm}[2022/04/07 v2.0 Draw liftarms with TikZ]
-\RequirePackage{etoolbox}
\RequirePackage[dvipsnames]{xcolor}
\RequirePackage{tikz}
\usetikzlibrary{calc}
-\newif\ifliftarm@animate
-\newif\ifliftarm@brick
-\newif\ifliftarm@connectreverse
-\newif\ifliftarm@contour
-\pgfkeys{
-/liftarm/.is family,
-/liftarm/.unknown/.code={\edef\liftarm@colorkey{\pgfkeyscurrentname}},
-/liftarm,
-axle holes/.store in=\liftarm@axleholes,
-brick/.is if=liftarm@brick,
-color/.store in=\liftarm@colorkey,
-color 0/.initial=Gray,
-color 1/.initial=darkgray,
-color 2/.initial=Yellow,
-color 3/.initial=Orange,
-color 4/.initial=Red,
-color 5/.initial=Green,
-color 6/.initial=Blue,
-color 7/.initial=Brown,
-color modulo/.initial=8,
-connect/.store in=\liftarm@connect,
-connect coordinate/.store in=\liftarm@connectcoordinate,
-connect reverse/.is if=liftarm@connectreverse,
-contour/.is if=liftarm@contour,
-coordinate/.store in=\liftarm@coordinate,
-globalize/.code n args={2}{\xdef#1{#2}},
-hole radius/.initial=0.3,
-liftarm 1/.style={liftarm 1 options/.style={#1}},
-liftarm 1 options/.style={},
-liftarm 2/.style={liftarm 2 options/.style={#1}},
-liftarm 2 options/.style={},
-liftarm thickness/.initial=0.92,
-mark color/.initial=Black,
-mark holes/.store in=\liftarm@markholes,
-origin/.initial=0,
-scalefactor/.initial=0.5,
-screw color/.initial=Black,
-screw holes/.store in=\liftarm@screwholes,
-screw holes angle/.initial=45,
-trace/.store in=\liftarm@trace,
-}
-\pgfmathsetmacro{\liftarm@axleholeangle}{14}%2*\liftarm@axleholeradius*sin(\liftarm@axleholeangle)=1.78/8
-\pgfmathsetmacro{\liftarm@screwholestartangle}{10}
-\newcommand{\liftarm}[4][]{
-\pgfmathsetmacro{\liftarm@length}{#3}
-\ifdim \liftarm@length pt<0 pt
-\PackageWarning{liftarm}{The length (\liftarm@length) of the liftarm is smaller than 0.}
-\else
-\pgfmathsetmacro{\liftarm@ang}{#4}
-\begin{scope}[shift={(#2)},rotate=\liftarm@ang]
-\pgfkeys{/liftarm,#1}
-\pgfmathsetmacro{\liftarm@origin}{\pgfkeysvalueof{/liftarm/origin}}
-\begin{scope}[shift={(-\liftarm@origin,0)}]
-\pgfmathsetmacro{\liftarm@halfthickness}{0.5*\pgfkeysvalueof{/liftarm/scalefactor}*\pgfkeysvalueof{/liftarm/liftarm thickness}}
-\pgfmathsetmacro{\liftarm@holeradius}{\pgfkeysvalueof{/liftarm/scalefactor}*\pgfkeysvalueof{/liftarm/hole radius}}
-\pgfmathsetmacro{\liftarm@halfstudwidth}{\pgfkeysvalueof{/liftarm/scalefactor}*0.3}
-\pgfmathsetmacro{\liftarm@studheight}{\pgfkeysvalueof{/liftarm/scalefactor}*0.2}
-\pgfmathsetmacro{\liftarm@halfplateheight}{\pgfkeysvalueof{/liftarm/scalefactor}*0.2}
-\pgfmathsetmacro{\liftarm@halfplatewidth}{\pgfkeysvalueof{/liftarm/scalefactor}*0.5}
-\pgfmathsetmacro{\liftarm@axleholeradius}{\liftarm@halfthickness}
-\pgfmathsetmacro{\liftarm@screwholeradius}{0.8*\liftarm@holeradius}
-\colorlet{liftarm@markcolor}{\pgfkeysvalueof{/liftarm/mark color}}
-\colorlet{liftarm@screwcolor}{\pgfkeysvalueof{/liftarm/screw color}}
-\pgfmathsetmacro{\liftarm@screwholesangle}{\pgfkeysvalueof{/liftarm/screw holes angle}}
-\ifcsname liftarm@colorkey\endcsname
-\colorlet{liftarm@color}{\liftarm@colorkey}
-\else
-\pgfmathsetmacro{\liftarm@colornumber}{int(mod(\liftarm@length,\pgfkeysvalueof{/liftarm/color modulo}))}
-\colorlet{liftarm@color}{\pgfkeysvalueof{/liftarm/color \liftarm@colornumber}}
-\fi
-\ifliftarm@brick
-\def\liftarm@shape{(-1,{-\liftarm@halfplatewidth-\liftarm@halfplateheight})--(-1,\liftarm@halfplatewidth)
-\foreach\liftarm@n in {-1,...,\liftarm@length}{
---({\liftarm@n+0.5-\liftarm@halfstudwidth},\liftarm@halfplatewidth)--({\liftarm@n+0.5-\liftarm@halfstudwidth},{\liftarm@halfplatewidth+\liftarm@studheight})--({\liftarm@n+0.5+\liftarm@halfstudwidth},{\liftarm@halfplatewidth+\liftarm@studheight})--({\liftarm@n+0.5+\liftarm@halfstudwidth},\liftarm@halfplatewidth)--({\liftarm@n+1},\liftarm@halfplatewidth)
-}
---({\liftarm@length+1},{-\liftarm@halfplatewidth-\liftarm@halfplateheight})--cycle}
-\else
-\def\liftarm@shape{(0,\liftarm@halfthickness) arc (90:270:\liftarm@halfthickness)--(\liftarm@length,-\liftarm@halfthickness) arc (-90:90:\liftarm@halfthickness)--cycle}
-\fi
-\fill[liftarm@color,even odd rule] \liftarm@shape
-\foreach\liftarm@n in {0,...,\liftarm@length}{
-(\liftarm@n,0) circle[radius=\liftarm@holeradius]
-};
-\ifliftarm@contour
-%\ifliftarm@brick
-%\else
-\draw[liftarm@color!75!Black,ultra thick] \liftarm@shape;
-%\fi
-\fi
-\ifcsname liftarm@axleholes\endcsname
-\foreach\liftarm@n in \liftarm@axleholes{
-\pgfmathsetmacro{\liftarm@axlehole}{\liftarm@n}
-\ifdim \liftarm@axlehole pt<0 pt
-\else
-\ifdim \liftarm@axlehole pt>\liftarm@length pt
-\else
-\foreach\liftarm@angle in {0,90,180,270}{
-\begin{scope}[shift={(\liftarm@axlehole,0)},rotate=\liftarm@angle]
-\fill[liftarm@color] (\liftarm@axleholeangle:\liftarm@axleholeradius) arc (\liftarm@axleholeangle:{90-\liftarm@axleholeangle}:\liftarm@axleholeradius)--({\liftarm@axleholeradius*sin(\liftarm@axleholeangle)},{\liftarm@axleholeradius*sin(\liftarm@axleholeangle)})--cycle;
-\end{scope}
-}
-\fi
-\fi
-}
-\fi
-\ifcsname liftarm@markholes\endcsname
-\foreach\liftarm@n in \liftarm@markholes{
-\pgfmathsetmacro{\liftarm@markhole}{\liftarm@n}
-\ifdim \liftarm@markhole pt<0 pt
-\else
-\ifdim \liftarm@markhole pt>\liftarm@length pt
-\else
-\fill[liftarm@markcolor] (\liftarm@markhole,0) circle[radius=\liftarm@holeradius];
-\fi
-\fi
-}
-\fi
-\ifcsname liftarm@screwholes\endcsname
-\foreach\liftarm@n in \liftarm@screwholes{
-\pgfmathsetmacro{\liftarm@screwhole}{\liftarm@n}
-\ifdim \liftarm@screwhole pt<0 pt
-\else
-\ifdim \liftarm@screwhole pt>\liftarm@length pt
-\else
-\begin{scope}[shift={(\liftarm@screwhole,0)},rotate=\liftarm@screwholesangle]
-\foreach\liftarm@n in {-1,1}{
-\fill[liftarm@screwcolor] ({\liftarm@screwholeradius*cos(\liftarm@screwholestartangle)},{\liftarm@n*\liftarm@screwholeradius*sin(\liftarm@screwholestartangle)}) arc ({\liftarm@n*\liftarm@screwholestartangle}:{\liftarm@n*(180-\liftarm@screwholestartangle)}:\liftarm@screwholeradius);
-}
-\end{scope}
-\fi
-\fi
-}
-\fi
-\ifcsname liftarm@coordinate\endcsname
-\foreach\liftarm@n/\liftarm@name in \liftarm@coordinate{
-\pgfmathsetmacro{\liftarm@value}{\liftarm@n}
-\coordinate (\liftarm@name) at (\liftarm@value,0);
-}
-\fi
-\ifcsname liftarm@trace\endcsname
-\ifliftarm@animate
-\foreach\liftarm@n/\liftarm@numberofframes/\liftarm@tracefigure in \liftarm@trace{
-\pgfmathsetmacro{\liftarm@value}{\liftarm@n}
-\gappto\liftarm@animateframestrace{\newframe\begin{scope}}
-\addtocounter{liftarm@animateframenumber}{1}
-\xappto\liftarm@animateframestrace{[shift={(#2)},rotate=\liftarm@ang]}
-\gappto\liftarm@animateframestrace{\begin{scope}}
-\xappto\liftarm@animateframestrace{[shift={(\liftarm@value-\liftarm@origin,0)}]}
-\ifdefempty{\liftarm@tracefigure}{
-\gappto\liftarm@animateframestrace{\fill[Black] (0,0) circle}
-\xappto\liftarm@animateframestrace{[radius=0.66*\liftarm@holeradius];}
-}
-{
-\xappto\liftarm@animateframestrace{\expandonce\liftarm@tracefigure}
-}
-\gappto\liftarm@animateframestrace{\end{scope}\end{scope}}
-\ifdefempty{\liftarm@numberofframes}{
-\csxappto{liftarm@animatetimeline0}{\theliftarm@animateframenumber x0,}
-}
-{
-\csxappto{liftarm@animatetimeline\theliftarm@animatestepnumber}{\theliftarm@animateframenumber x\liftarm@numberofframes,}
-}
-}
-\fi
-\fi
-\end{scope}
-\end{scope}
-\fi
-}
-\newcommand{\liftarmconnect}[5][]{
-\begin{scope}
-\pgfkeys{/liftarm,#1}
-\coordinate (liftarm@A) at (#2);
-\coordinate (liftarm@B) at (#4);
-\begin{scope}
-\pgfkeys{/liftarm,liftarm 1 options}
-\ifcsname liftarm@connect\endcsname
-\pgfmathsetmacro{\liftarm@connectlengthAtemp}{\liftarm@connect-\pgfkeysvalueof{/liftarm/origin}}
-\else
-\pgfmathsetmacro{\liftarm@connectlengthAtemp}{#3-\pgfkeysvalueof{/liftarm/origin}}
-\fi
-\xdef\liftarm@connectlengthA{\liftarm@connectlengthAtemp}
-\ifdim \liftarm@connectlengthA pt=0 pt
-\PackageWarning{liftarm}{The length of the first liftarm is 0.}
-\fi
-\end{scope}
-\begin{scope}
-\pgfkeys{/liftarm,liftarm 2 options}
-\ifcsname liftarm@connect\endcsname
-\pgfmathsetmacro{\liftarm@connectlengthBtemp}{\liftarm@connect-\pgfkeysvalueof{/liftarm/origin}}
-\else
-\pgfmathsetmacro{\liftarm@connectlengthBtemp}{#5-\pgfkeysvalueof{/liftarm/origin}}
-\fi
-\xdef\liftarm@connectlengthB{\liftarm@connectlengthBtemp}
-\ifdim \liftarm@connectlengthB pt=0 pt
-\PackageWarning{liftarm}{The length of the second liftarm is 0.}
-\fi
-\end{scope}
-\path
-let
-\p1=(liftarm@A),
-\p2=(liftarm@B),
-\n1={\x1/\pgf@xx},
-\n2={\y1/\pgf@yy},
-\n3={\x2/\pgf@xx},
-\n4={\y2/\pgf@yy}
-in
-[
-/liftarm/globalize={\liftarm@connectxalet}{\n3},
-/liftarm/globalize={\liftarm@connectyalet}{\n4},
-/liftarm/globalize={\liftarm@connectxblet}{\n1},
-/liftarm/globalize={\liftarm@connectyblet}{\n2}
-]
-;
-\pgfmathsetmacro{\liftarm@connectxa}{\liftarm@connectxalet}
-\pgfmathsetmacro{\liftarm@connectya}{\liftarm@connectyalet}
-\pgfmathsetmacro{\liftarm@connectxb}{\liftarm@connectxblet}
-\pgfmathsetmacro{\liftarm@connectyb}{\liftarm@connectyblet}
-\pgfmathsetmacro{\liftarm@absdiff}{abs(\liftarm@connectxa-\liftarm@connectxb)}
-\ifdim \liftarm@absdiff pt<0.001 pt
-\pgfmathsetmacro{\liftarm@connectanglegamma}{90}
-\ifdim \liftarm@connectya pt<\liftarm@connectyb pt
-\pgfmathsetmacro{\liftarm@connectangleshift}{0}
-\else
-\pgfmathsetmacro{\liftarm@connectangleshift}{180}
-\fi
-\else
-\pgfmathsetmacro{\liftarm@connectanglegamma}{atan((\liftarm@connectyb-\liftarm@connectya)/(\liftarm@connectxb-\liftarm@connectxa))}
-\ifdim \liftarm@connectxa pt<\liftarm@connectxb pt
-\pgfmathsetmacro{\liftarm@connectangleshift}{0}
-\else
-\pgfmathsetmacro{\liftarm@connectangleshift}{180}
-\fi
-\fi
-\pgfmathsetmacro{\liftarm@connectlength}{sqrt((\liftarm@connectyb-\liftarm@connectya)^2+(\liftarm@connectxb-\liftarm@connectxa)^2)}
-\ifdim \liftarm@connectlength pt=0 pt
-\PackageWarning{liftarm}{The length between the origins of the liftarms is 0.}
-\fi
-\pgfmathsetmacro{\liftarm@connectabsconnectlengthAminusconnectlengthB}{abs(\liftarm@connectlengthA-\liftarm@connectlengthB)}
-\ifdim \liftarm@connectabsconnectlengthAminusconnectlengthB pt>\liftarm@connectlength pt
-\PackageWarning{liftarm}{The liftarms can not be connected.}
-\fi
-\pgfmathsetmacro{\liftarm@connectconnectlengthAplusconnectlengthB}{\liftarm@connectlengthA+\liftarm@connectlengthB}
-\ifdim \liftarm@connectconnectlengthAplusconnectlengthB pt<\liftarm@connectlength pt
-\PackageWarning{liftarm}{The liftarms can not be connected.}
-\fi
-\pgfmathsetmacro{\liftarm@connectanglealpha}{acos(((\liftarm@connectlengthB)^2+(\liftarm@connectlength)^2-(\liftarm@connectlengthA)^2)/(2*(\liftarm@connectlength)*(\liftarm@connectlengthB)))}
-\pgfmathsetmacro{\liftarm@connectanglebeta}{acos(((\liftarm@connectlength)^2+(\liftarm@connectlengthA)^2-(\liftarm@connectlengthB)^2)/(2*\liftarm@connectlength*(\liftarm@connectlengthA)))}
-\pgfmathsetmacro{\liftarm@connectangledelta}{\liftarm@connectangleshift+180+\liftarm@connectanglegamma-\liftarm@connectanglebeta}
-\def\liftarm@liftarmA{\liftarm[liftarm 1 options]{#2}{#3}{\liftarm@connectangledelta}}
-\def\liftarm@liftarmB{\liftarm[liftarm 2 options]{#4}{#5}{\liftarm@connectangleshift+\liftarm@connectanglegamma+\liftarm@connectanglealpha}}
-\ifliftarm@connectreverse
-\liftarm@liftarmB
-\liftarm@liftarmA
-\else
-\liftarm@liftarmA
-\liftarm@liftarmB
-\fi
-\ifcsname liftarm@connectcoordinate\endcsname
-\coordinate (\liftarm@connectcoordinate) at ($(#2)+(\liftarm@connectangledelta:\liftarm@connectlengthA)$);
-\fi
-\end{scope}
-}
-\newcommand{\liftarm@construction}[2][]{\begin{tikzpicture}[#1]
-\liftarm@constructfigure
-#2
-\end{tikzpicture}}
-\newcommand{\liftarmconstruct}[3][]{\item #2\nopagebreak
+\ProvidesExplPackage{liftarm}{2024/05/20}{3.0}{Geometric constructions with liftarms using TikZ and LaTeX3}
+
+%%> \subsection{Variables}
+
+\newcounter { g__liftarm_animate_frame_number_counter }
+\newcounter { g__liftarm_animate_number_of_animation_counter }
+\newcounter { g__liftarm_animate_number_of_steps_counter }
+\newcounter { g__liftarm_animate_step_number_counter }
+
+\bool_new:N \l__liftarm_animate_bool
+\bool_new:N \l__liftarm_brick_bool
+\bool_new:N \l__liftarm_contour_bool
+\bool_new:N \l__liftarm_LU_bool
+
+\clist_new:N \l__liftarm_trace_clist
+
+\fp_new:N \l__liftarm_angle_fp
+\fp_const:Nn \c__liftarm_axle_hole_angle_fp { 21.76702028497987 }%asind ( 1.78 / ( 16 * 0.3 ) )
+\fp_new:N \l__liftarm_connect_det_fp
+\fp_new:N \l__liftarm_connect_norm_fp
+\fp_new:N \l__liftarm_connect_start_constant_x_fp
+\fp_new:N \l__liftarm_connect_start_constant_y_fp
+\fp_new:N \l__liftarm_connect_stop_value_fp
+\fp_new:c { l__liftarm_connect_two_1_option_0_angle_fp }
+\fp_new:c { l__liftarm_connect_two_1_option_1_angle_fp }
+\fp_new:c { l__liftarm_connect_two_2_option_0_angle_fp }
+\fp_new:c { l__liftarm_connect_two_2_option_1_angle_fp }
+\fp_new:N \l__liftarm_connect_two_angle_fp
+\fp_new:N \l__liftarm_connect_two_A_angle_fp
+\fp_new:N \l__liftarm_connect_two_A_length_fp
+\fp_new:N \l__liftarm_connect_two_A_x_fp
+\fp_new:N \l__liftarm_connect_two_A_y_fp
+\fp_new:N \l__liftarm_connect_two_B_angle_fp
+\fp_new:N \l__liftarm_connect_two_B_length_fp
+\fp_new:N \l__liftarm_connect_two_B_x_fp
+\fp_new:N \l__liftarm_connect_two_B_y_fp
+\fp_new:N \l__liftarm_connect_two_length_fp
+\fp_new:N \g__liftarm_coord_x_fp
+\fp_new:N \g__liftarm_coord_y_fp
+\fp_new:N \l__liftarm_half_thickness_fp
+\fp_new:N \l__liftarm_hole_radius_fp
+\fp_new:N \l__liftarm_length_fp
+\fp_new:N \l__liftarm_LU_maxA_fp
+\fp_new:N \l__liftarm_LU_tmp_fp
+\fp_new:N \l__liftarm_mark_radius_fp
+\fp_new:N \l__liftarm_origin_fp
+\fp_new:N \l__liftarm_origin_connect_initial_fp
+\fp_new:N \l__liftarm_scalefactor_fp
+\fp_new:N \l__liftarm_screw_angle_fp
+\fp_new:N \l__liftarm_screw_radius_fp
+
+\int_new:N \l__liftarm_connect_count_int
+\int_new:N \l__liftarm_connect_equation_int
+\int_new:N \l__liftarm_LU_count_int
+\int_new:N \l__liftarm_LU_imax_int
+\int_new:N \l__liftarm_LU_j_int
+\int_new:N \l__liftarm_LU_N_int
+
+\iow_new:N \g__liftarm_animate_write_timeline_iow
+
+\seq_new:N \l__liftarm_connect_coordinate_seq
+\seq_new:N \l__liftarm_connect_start_arg_seq
+\seq_new:N \l__liftarm_connect_start_coeff_seq
+\seq_new:N \l__liftarm_coordinate_seq
+\seq_new:N \l__liftarm_trace_item_seq
+
+\str_new:N \l__liftarm_connect_stop_type_str
+\str_new:N \l__liftarm_type_str
+
+\tl_new:N \g__liftarm_animate_frames_tl
+\tl_new:N \g__liftarm_animate_frames_trace_tl
+\tl_new:N \l__liftarm_animate_value_tl
+\tl_new:N \l__liftarm_color_tl
+\tl_new:N \g__liftarm_construct_tl
+\tl_const:Nn \c__liftarm_cos_sin_diff_x_tl { - sin }
+\tl_const:Nn \c__liftarm_cos_sin_diff_y_tl { cos }
+\tl_const:Nn \c__liftarm_cos_sin_x_tl { cos }
+\tl_const:Nn \c__liftarm_cos_sin_y_tl { sin }
+\tl_new:N \l__liftarm_holes_tl
+\tl_new:N \l__liftarm_shape_tl
+\tl_new:N \l__liftarm_tmp_tl
+
+%%> \subsection{Pgfkeys}
+
+\pgfkeys
+ {
+ / liftarm /. is~family ,
+ / liftarm ,
+ axle~holes /. initial = {} ,
+ brick /. code = { \bool_set:Nn \l__liftarm_brick_bool { \cs:w c_#1_bool\cs_end: } } ,
+ brick /. default = true ,
+ brick = false ,
+ color /. code~2~args =
+ {
+ \tl_clear_new:c { l__liftarm_color_\int_eval:n {#1}_tl }
+ \tl_set:cn { l__liftarm_color_\int_eval:n {#1}_tl } {#2}
+ } ,
+ color = { 0 } { Gray } ,
+ color = { 1 } { darkgray } ,
+ color = { 2 } { Yellow } ,
+ color = { 3 } { Orange } ,
+ color = { 4 } { Red } ,
+ color = { 5 } { Green } ,
+ color = { 6 } { Blue } ,
+ color = { 7 } { Brown } ,
+ color~modulo /. initial = 8 ,
+ connect~stop /. is~choice ,
+ connect~stop / 1-norm /. code =
+ {
+ \str_set:Nn \l__liftarm_connect_stop_type_str { 1-norm }
+ \fp_set:Nn \l__liftarm_connect_stop_value_fp {#1}
+ } ,
+ connect~stop / 1-norm /. default = 0.001 ,
+ connect~stop / 2-norm /. code =
+ {
+ \str_set:Nn \l__liftarm_connect_stop_type_str { 2-norm }
+ \fp_set:Nn \l__liftarm_connect_stop_value_fp {#1}
+ } ,
+ connect~stop / 2-norm /. default = 0.001 ,
+ connect~stop / iterations /. code =
+ {
+ \str_set:Nn \l__liftarm_connect_stop_type_str { iterations }
+ \fp_set:Nn \l__liftarm_connect_stop_value_fp {#1}
+ } ,
+ connect~stop / iterations /. default = 10 ,
+ connect~stop = 1-norm ,
+ contour /. code = { \bool_set:Nn \l__liftarm_contour_bool { \cs:w c_#1_bool\cs_end: } } ,
+ contour /. default = true ,
+ contour = false ,
+ contour~style /. style = { contour_style /. style = {#1} } ,
+ contour_style /. style = {} ,
+ coordinate /. initial = {} ,
+ hole~radius /. initial = 0.3 ,
+ liftarm~style /. style = { liftarm_style /. style = {#1} } ,
+ liftarm_style /. style = {} ,
+ liftarm~thickness /. initial = 0.92 ,
+ mark~holes /. initial = {} ,
+ mark~radius /. code =
+ {
+ \pgfmathparse {#1}
+ \fp_set:Nn \l__liftarm_mark_radius_fp { \pgfmathresult }
+ } ,
+ mark~radius = 1 ,
+ mark~style /. style = { mark_style /. style = {#1} } ,
+ mark_style /. style = {} ,
+ origin /. code =
+ {
+ \pgfmathparse {#1}
+ \fp_set:Nn \l__liftarm_origin_fp { \pgfmathresult }
+ } ,
+ origin = 0 ,
+ scalefactor /. code =
+ {
+ \pgfmathparse {#1}
+ \fp_set:Nn \l__liftarm_scalefactor_fp { \pgfmathresult }
+ } ,
+ scalefactor = 0.5 ,
+ screw~angle /. code =
+ {
+ \pgfmathparse {#1}
+ \fp_set:Nn \l__liftarm_screw_angle_fp { \pgfmathresult }
+ } ,
+ screw~angle = 10 ,
+ screw~holes /. initial = {} ,
+ screw~radius /. code =
+ {
+ \pgfmathparse {#1}
+ \fp_set:Nn \l__liftarm_screw_radius_fp { \pgfmathresult }
+ } ,
+ screw~radius = 0.8 ,
+ screw~style /. style = { screw_style /. style = {#1} } ,
+ screw_style /. style = {} ,
+ trace /. code = { \clist_set:Nn \l__liftarm_trace_clist {#1} } ,
+ type /. is~choice ,
+ type / liftarm /. code = { \str_set:Nn \l__liftarm_type_str { liftarm } } ,
+ type / liftarm /. value~forbidden ,
+ type / line~segment /. code = { \str_set:Nn \l__liftarm_type_str { line~segment } } ,
+ type / line~segment /. value~forbidden ,
+ type = liftarm ,
+ }
+
+\pgfkeys
+ {
+ / liftarm / connect_algorithm /. is~family ,
+ / liftarm / connect_algorithm /. unknown /. code = {} ,
+ / liftarm / connect_algorithm ,
+ coordinate /. initial = {} ,
+ origin /. code =
+ {
+ \pgfmathparse {#1}
+ \fp_set:Nn \l__liftarm_origin_fp { \pgfmathresult }
+ } ,
+ }
+
+%%> \subsection{Functions}
+
+\cs_generate_variant:Nn \clist_if_in:nnTF { enTF }
+\cs_generate_variant:Nn \clist_map_inline:nn { en }
+\cs_generate_variant:Nn \seq_map_indexed_inline:Nn { cn }
+\cs_generate_variant:Nn \tl_build_begin:N { c }
+\cs_generate_variant:Nn \tl_build_gbegin:N { c }
+\cs_generate_variant:Nn \tl_build_end:N { c }
+\cs_generate_variant:Nn \tl_build_gend:N { c }
+\cs_generate_variant:Nn \tl_build_put_right:Nn { ce , cn }
+\cs_generate_variant:Nn \tl_build_gput_right:Nn { ce , cn }
+
+\cs_new_protected:Npn \__liftarm_connect:nnnn #1#2#3#4
+ {
+ \int_incr:N \l__liftarm_connect_count_int
+ \fp_zero_new:c { l__liftarm_connect_angle_\int_use:N \l__liftarm_connect_count_int _fp }
+ \pgfmathparse {#4}
+ \fp_set:cn { l__liftarm_connect_angle_\int_use:N \l__liftarm_connect_count_int _fp } { \pgfmathresult * deg }
+ \fp_set_eq:NN \l__liftarm_origin_fp \l__liftarm_origin_connect_initial_fp
+ \pgfkeys
+ {
+ / liftarm / connect_algorithm ,
+ coordinate = \pgfkeysvalueof { / liftarm / coordinate } ,
+ #1
+ }
+ \seq_if_in:NnTF \l__liftarm_connect_coordinate_seq {#2}
+ {
+ \fp_set_eq:Nc \l__liftarm_connect_start_constant_x_fp { l__liftarm_connect_constant_x_coord_#2_fp }
+ \fp_set_eq:Nc \l__liftarm_connect_start_constant_y_fp { l__liftarm_connect_constant_y_coord_#2_fp }
+ \seq_set_eq:Nc \l__liftarm_connect_start_arg_seq { l__liftarm_connect_arg_coord_#2_seq }
+ \seq_set_eq:Nc \l__liftarm_connect_start_coeff_seq { l__liftarm_connect_coeff_coord_#2_seq }
+ }
+ {
+ \__liftarm_def_coord:n {#2}
+ \fp_set_eq:NN \l__liftarm_connect_start_constant_x_fp \g__liftarm_coord_x_fp
+ \fp_set_eq:NN \l__liftarm_connect_start_constant_y_fp \g__liftarm_coord_y_fp
+ \seq_clear:N \l__liftarm_connect_start_arg_seq
+ \seq_clear:N \l__liftarm_connect_start_coeff_seq
+ }
+ \clist_map_inline:en { \pgfkeysvalueof { / liftarm / connect_algorithm / coordinate } }
+ {
+ \seq_set_split:Nnn \l__liftarm_coordinate_seq { / } {##1}
+ \pgfmathparse { \seq_item:Nn \l__liftarm_coordinate_seq { 1 } }
+ \fp_set:Nn \l__liftarm_length_fp { \pgfmathresult - \l__liftarm_origin_fp }
+ \seq_if_in:NeTF \l__liftarm_connect_coordinate_seq { \seq_item:Nn \l__liftarm_coordinate_seq { 2 } }
+ {
+ \clist_map_inline:nn { x , y }
+ {
+ \int_incr:N \l__liftarm_connect_equation_int
+ \tl_clear_new:c { l__liftarm_connect_F_\int_use:N \l__liftarm_connect_equation_int _tl }
+ \tl_build_begin:c { l__liftarm_connect_F_\int_use:N \l__liftarm_connect_equation_int _tl }
+ \int_step_inline:nn { \l__liftarm_LU_N_int }
+ {
+ \tl_clear_new:c { l__liftarm_connect_Jacobian_\int_use:N \l__liftarm_connect_equation_int _########1_tl }
+ \tl_build_begin:c { l__liftarm_connect_Jacobian_\int_use:N \l__liftarm_connect_equation_int _########1_tl }
+ \tl_build_put_right:cn { l__liftarm_connect_Jacobian_\int_use:N \l__liftarm_connect_equation_int _########1_tl }
+ { 0 }
+ \fp_zero_new:c { l__liftarm_LU_A_\int_use:N \l__liftarm_connect_equation_int _########1_fp }
+ }
+ \tl_build_put_right:ce { l__liftarm_connect_F_\int_use:N \l__liftarm_connect_equation_int _tl }
+ {
+ \fp_use:c { l__liftarm_connect_constant_####1_coord_\seq_item:Nn \l__liftarm_coordinate_seq { 2 }_fp }
+ - \fp_use:c { l__liftarm_connect_start_constant_####1_fp }
+ - \fp_use:N \l__liftarm_length_fp * \cs:w c__liftarm_cos_sin_####1_tl\cs_end:
+ ( \exp_not:N \cs:w l__liftarm_connect_angle_\int_use:N \l__liftarm_connect_count_int _fp \exp_not:N \cs_end: )
+ }
+ \tl_build_put_right:ce
+ {
+ l__liftarm_connect_Jacobian_\int_use:N \l__liftarm_connect_equation_int _
+ \int_use:N \l__liftarm_connect_count_int _tl
+ }
+ {
+ - \fp_use:N \l__liftarm_length_fp * \cs:w c__liftarm_cos_sin_diff_####1_tl\cs_end:
+ ( \exp_not:N \cs:w l__liftarm_connect_angle_\int_use:N \l__liftarm_connect_count_int _fp \exp_not:N \cs_end: )
+ }
+ \seq_map_indexed_inline:cn { l__liftarm_connect_arg_coord_\seq_item:Nn \l__liftarm_coordinate_seq { 2 }_seq }
+ {
+ \tl_build_put_right:ce { l__liftarm_connect_F_\int_use:N \l__liftarm_connect_equation_int _tl }
+ {
+ + \seq_item:cn { l__liftarm_connect_coeff_coord_\seq_item:Nn \l__liftarm_coordinate_seq { 2 }_seq } {########1}
+ * \cs:w c__liftarm_cos_sin_####1_tl\cs_end:
+ ( \exp_not:N \cs:w l__liftarm_connect_angle_########2_fp \exp_not:N \cs_end: )
+ }
+ \tl_build_put_right:ce { l__liftarm_connect_Jacobian_\int_use:N \l__liftarm_connect_equation_int _########2_tl }
+ {
+ + \seq_item:cn { l__liftarm_connect_coeff_coord_\seq_item:Nn \l__liftarm_coordinate_seq { 2 }_seq } {########1}
+ * \cs:w c__liftarm_cos_sin_diff_####1_tl\cs_end:
+ ( \exp_not:N \cs:w l__liftarm_connect_angle_########2_fp \exp_not:N \cs_end: )
+ }
+ }
+ \seq_map_indexed_inline:Nn \l__liftarm_connect_start_arg_seq
+ {
+ \tl_build_put_right:ce { l__liftarm_connect_F_\int_use:N \l__liftarm_connect_equation_int _tl }
+ {
+ - \seq_item:Nn \l__liftarm_connect_start_coeff_seq {########1} * \cs:w c__liftarm_cos_sin_####1_tl\cs_end:
+ ( \exp_not:N \cs:w l__liftarm_connect_angle_########2_fp \exp_not:N \cs_end: )
+ }
+ \tl_build_put_right:ce { l__liftarm_connect_Jacobian_\int_use:N \l__liftarm_connect_equation_int _########2_tl }
+ {
+ - \seq_item:Nn \l__liftarm_connect_start_coeff_seq {########1} * \cs:w c__liftarm_cos_sin_diff_####1_tl\cs_end:
+ ( \exp_not:N \cs:w l__liftarm_connect_angle_########2_fp \exp_not:N \cs_end: )
+ }
+ }
+ \tl_build_end:c { l__liftarm_connect_F_\int_use:N \l__liftarm_connect_equation_int _tl }
+ \int_step_inline:nn { \l__liftarm_LU_N_int }
+ { \tl_build_end:c { l__liftarm_connect_Jacobian_\int_use:N \l__liftarm_connect_equation_int _########1_tl } }
+ }
+ }
+ {
+ \clist_map_inline:nn { x , y }
+ {
+ \fp_zero_new:c { l__liftarm_connect_constant_####1_coord_\seq_item:Nn \l__liftarm_coordinate_seq { 2 }_fp }
+ \fp_set_eq:cc { l__liftarm_connect_constant_####1_coord_\seq_item:Nn \l__liftarm_coordinate_seq { 2 }_fp }
+ { l__liftarm_connect_start_constant_####1_fp }
+ }
+ \clist_map_inline:nn { arg , coeff }
+ {
+ \seq_clear_new:c { l__liftarm_connect_####1_coord_\seq_item:Nn \l__liftarm_coordinate_seq { 2 }_seq }
+ \seq_set_eq:cc { l__liftarm_connect_####1_coord_\seq_item:Nn \l__liftarm_coordinate_seq { 2 }_seq }
+ { l__liftarm_connect_start_####1_seq }
+ }
+ \seq_put_right:ce { l__liftarm_connect_arg_coord_\seq_item:Nn \l__liftarm_coordinate_seq { 2 }_seq }
+ { \int_use:N \l__liftarm_connect_count_int }
+ \seq_put_right:ce { l__liftarm_connect_coeff_coord_\seq_item:Nn \l__liftarm_coordinate_seq { 2 }_seq }
+ { \fp_use:N \l__liftarm_length_fp }
+ \seq_put_right:Ne \l__liftarm_connect_coordinate_seq { \seq_item:Nn \l__liftarm_coordinate_seq { 2 } }
+ }
+ }
+ }
+
+\cs_new_protected:Npn \__liftarm_connect_stop_criterion:
+ {
+ \int_step_inline:nn { \l__liftarm_LU_N_int }
+ { \fp_set:cn { l__liftarm_LU_b_##1_fp } { \cs:w l__liftarm_connect_F_##1_tl\cs_end: } }
+ \str_case:Vn \l__liftarm_connect_stop_type_str
+ {
+ { 1-norm }
+ {
+ \fp_zero:N \l__liftarm_connect_norm_fp
+ \int_step_inline:nn { \l__liftarm_LU_N_int }
+ { \fp_add:Nn \l__liftarm_connect_norm_fp { abs ( \cs:w l__liftarm_LU_b_##1_fp\cs_end: ) } }
+ \bool_set:Nn \l__liftarm_LU_bool
+ { \fp_compare_p:nNn { \l__liftarm_connect_norm_fp } > { \l__liftarm_connect_stop_value_fp } }
+ }
+ { 2-norm }
+ {
+ \fp_zero:N \l__liftarm_connect_norm_fp
+ \int_step_inline:nn { \l__liftarm_LU_N_int }
+ { \fp_add:Nn \l__liftarm_connect_norm_fp { ( \cs:w l__liftarm_LU_b_##1_fp\cs_end: ) ^ 2 } }
+ \bool_set:Nn \l__liftarm_LU_bool
+ { \fp_compare_p:nNn { sqrt ( \l__liftarm_connect_norm_fp ) } > { \l__liftarm_connect_stop_value_fp } }
+ }
+ { iterations }
+ {
+ \bool_set:Nn \l__liftarm_LU_bool
+ { \fp_compare_p:nNn { \l__liftarm_LU_count_int } < { \l__liftarm_connect_stop_value_fp } }
+ }
+ }
+ }
+
+\cs_new_protected:Npn \__liftarm_def_coord:n #1
+ {
+ \path let \p { l__liftarm_coord } = (#1) in
+ [
+ / utils / exec =
+ {
+ \fp_gset:Nn \g__liftarm_coord_x_fp
+ { ( \pgf@yy * \x { l__liftarm_coord } - \pgf@yx * \y { l__liftarm_coord } ) / \l__liftarm_connect_det_fp }
+ \fp_gset:Nn \g__liftarm_coord_y_fp
+ { ( \pgf@xx * \y { l__liftarm_coord } - \pgf@xy * \x { l__liftarm_coord } ) / \l__liftarm_connect_det_fp }
+ }
+ ] ;
+ }
+
+\cs_new_protected:Npn \__liftarm_default:nnnn #1#2#3#4
+ {
+ \pgfmathparse {#3}
+ \fp_set:Nn \l__liftarm_length_fp { \pgfmathresult }
+ \fp_compare:nNnTF { \l__liftarm_length_fp } < { 0 }
+ { \PackageWarning { liftarm } { The~length~( \fp_use:N \l__liftarm_length_fp )~of~the~liftarm~is~smaller~than~0. } }
+ {
+ \pgfmathparse {#4}
+ \fp_set:Nn \l__liftarm_angle_fp { \pgfmathresult }
+ \begin { scope }
+ [
+ shift = { (#2) } ,
+ rotate = \fp_use:N \l__liftarm_angle_fp
+ ]
+ \pgfkeys { / liftarm , #1 }
+ \tl_set:Ne \l__liftarm_color_tl
+ {
+ \cs:w
+ l__liftarm_color_
+ \int_mod:nn { \fp_eval:n { trunc ( \l__liftarm_length_fp , 0 ) } } { \pgfkeysvalueof { / liftarm / color~modulo } }_tl
+ \cs_end:
+ }
+ \begin { scope } [ shift = { ( - \fp_use:N \l__liftarm_origin_fp , 0 ) } ]
+ \str_case:Vn \l__liftarm_type_str
+ {
+ { liftarm }
+ {
+ \pgfmathparse { \pgfkeysvalueof { / liftarm / liftarm~thickness } }
+ \fp_set:Nn \l__liftarm_half_thickness_fp { 0.5 * \l__liftarm_scalefactor_fp * \pgfmathresult }
+ \pgfmathparse { \pgfkeysvalueof { / liftarm / hole~radius } }
+ \fp_set:Nn \l__liftarm_hole_radius_fp { \l__liftarm_scalefactor_fp * \pgfmathresult }
+ \bool_if:NTF \l__liftarm_brick_bool
+ {
+ \tl_build_begin:N \l__liftarm_shape_tl
+ \tl_build_put_right:Ne \l__liftarm_shape_tl
+ {
+ ( -1 , \fp_eval:n { - \l__liftarm_scalefactor_fp * 0.7 } )
+ -- ( -1 , \fp_eval:n { \l__liftarm_scalefactor_fp * 0.5 } )
+ }
+ \int_step_inline:nnn { -1 } { \fp_eval:n { trunc ( \l__liftarm_length_fp , 0 ) } }
+ {
+ \tl_build_put_right:Ne \l__liftarm_shape_tl
+ {
+ -- (
+ \fp_eval:n { ##1 + 0.5 - \l__liftarm_scalefactor_fp * 0.3 } ,
+ \fp_eval:n { \l__liftarm_scalefactor_fp * 0.5 }
+ )
+ --++ ( 0 , \fp_eval:n { \l__liftarm_scalefactor_fp * 0.2 } )
+ --++ ( \fp_eval:n { \l__liftarm_scalefactor_fp * 0.6 } , 0 )
+ --++ ( 0 , \fp_eval:n { - \l__liftarm_scalefactor_fp * 0.2 } )
+ }
+ }
+ \tl_build_put_right:Ne \l__liftarm_shape_tl
+ {
+ -- ( \fp_eval:n { \l__liftarm_length_fp + 1 } , \fp_eval:n { \l__liftarm_scalefactor_fp * 0.5 } )
+ --++ ( 0 , \fp_eval:n { - \l__liftarm_scalefactor_fp * 1.2 } )
+ -- cycle
+ }
+ \tl_build_end:N \l__liftarm_shape_tl
+ }
+ {
+ \tl_set:Ne \l__liftarm_shape_tl
+ {
+ ( 0 , \fp_use:N \l__liftarm_half_thickness_fp )
+ arc
+ [
+ start~angle = 90 ,
+ end~angle = 270 ,
+ radius = \fp_use:N \l__liftarm_half_thickness_fp
+ ]
+ -- ( \fp_use:N \l__liftarm_length_fp , - \fp_use:N \l__liftarm_half_thickness_fp )
+ arc
+ [
+ start~angle = -90 ,
+ end~angle = 90 ,
+ radius = \fp_use:N \l__liftarm_half_thickness_fp
+ ]
+ -- cycle
+ }
+ }
+ \tl_build_begin:N \l__liftarm_holes_tl
+ \int_step_inline:nnn { 0 } { \fp_eval:n { trunc ( \l__liftarm_length_fp , 0 ) } }
+ {
+ \clist_if_in:enTF { \pgfkeysvalueof { / liftarm / axle~holes } } {##1}
+ {
+ \int_step_inline:nn { 4 }
+ {
+ \tl_build_put_right:Ne \l__liftarm_holes_tl
+ {
+ (
+ \fp_eval:n
+ {
+ ##1 + sqrt ( 2 ) * \l__liftarm_hole_radius_fp * sind ( \c__liftarm_axle_hole_angle_fp )
+ * cosd ( ####1 * 90 - 45 )
+ } ,
+ \fp_eval:n { sqrt ( 2 ) * \l__liftarm_hole_radius_fp * sind ( \c__liftarm_axle_hole_angle_fp )
+ * sind ( ####1 * 90 - 45 ) }
+ )
+ -- (
+ \fp_eval:n
+ {
+ ##1
+ + \l__liftarm_hole_radius_fp * cosd ( ####1 * 90 - \c__liftarm_axle_hole_angle_fp )
+ } ,
+ \fp_eval:n { \l__liftarm_hole_radius_fp * sind ( ####1 * 90 - \c__liftarm_axle_hole_angle_fp ) }
+ )
+ arc
+ [
+ start~angle = \fp_eval:n { ####1 * 90 - \c__liftarm_axle_hole_angle_fp } ,
+ end~angle = \fp_eval:n { ####1 * 90 + \c__liftarm_axle_hole_angle_fp } ,
+ radius = \fp_use:N \l__liftarm_hole_radius_fp
+ ]
+ --
+ }
+ }
+ \tl_build_put_right:Nn \l__liftarm_holes_tl { cycle }
+ }
+ {
+ \tl_build_put_right:Ne \l__liftarm_holes_tl
+ { ( ##1 , 0 ) circle [ radius = \fp_use:N \l__liftarm_hole_radius_fp ] }
+ }
+ }
+ \tl_build_end:N \l__liftarm_holes_tl
+ \fill [ \l__liftarm_color_tl , even~odd~rule , / liftarm / liftarm_style ]
+ \l__liftarm_shape_tl \l__liftarm_holes_tl ;
+ \bool_if:NT \l__liftarm_contour_bool
+ { \draw [ \l__liftarm_color_tl ! 75 ! black , ultra~thick , / liftarm / contour_style ] \l__liftarm_shape_tl ; }
+ \clist_map_inline:en { \pgfkeysvalueof { / liftarm / mark~holes } }
+ {
+ \fill [ black , / liftarm / mark_style ]
+ ( {##1} , 0 ) circle [ radius = \fp_eval:n { \l__liftarm_mark_radius_fp * \l__liftarm_hole_radius_fp } ] ;
+ }
+ \clist_map_inline:en { \pgfkeysvalueof { / liftarm / screw~holes } }
+ {
+ \clist_map_inline:nn { -1 , 1 }
+ {
+ \fill [ black , shift = { ( {##1} , 0 ) } , rotate = 45 , / liftarm / screw_style ]
+ (
+ \fp_eval:n { ####1 * \l__liftarm_screw_angle_fp }
+ \c_colon_str
+ \fp_eval:n { \l__liftarm_screw_radius_fp * \l__liftarm_hole_radius_fp }
+ )
+ arc
+ [
+ start~angle = \fp_eval:n { ####1 * \l__liftarm_screw_angle_fp } ,
+ end~angle = \fp_eval:n { ####1 * ( 180 - \l__liftarm_screw_angle_fp ) } ,
+ radius = \fp_eval:n { \l__liftarm_screw_radius_fp * \l__liftarm_hole_radius_fp }
+ ]
+ ;
+ }
+ }
+ }
+ { line~segment }
+ {
+ \draw [ \l__liftarm_color_tl , / liftarm / liftarm_style ] ( 0 , 0 ) -- ( \fp_use:N \l__liftarm_length_fp , 0 ) ;
+ }
+ }
+ \clist_map_inline:en { \pgfkeysvalueof { / liftarm / coordinate } }
+ {
+ \seq_set_split:Nnn \l__liftarm_coordinate_seq { / } {##1}
+ \coordinate ( \seq_item:Nn \l__liftarm_coordinate_seq { 2 } )
+ at ( { \seq_item:Nn \l__liftarm_coordinate_seq { 1 } } , 0 ) ;
+ }
+ \bool_if:NT \l__liftarm_animate_bool
+ {
+ \clist_map_inline:Nn \l__liftarm_trace_clist
+ {
+ \seq_set_split:Nnn \l__liftarm_trace_item_seq { / } {##1}
+ \stepcounter { g__liftarm_animate_frame_number_counter }
+ \tl_build_gput_right:Ne \g__liftarm_animate_frames_trace_tl
+ {
+ \exp_not:n { \newframe \begin } { scope }
+ [ shift = { (#2) } , rotate = \fp_use:N \l__liftarm_angle_fp ]
+ \exp_not:N \begin { scope }
+ [ shift = { ( \fp_eval:n { \seq_item:Nn \l__liftarm_trace_item_seq { 1 } - \l__liftarm_origin_fp } , 0 ) } ]
+ \tl_if_empty:eTF { \seq_item:Nn \l__liftarm_trace_item_seq { 3 } }
+ {
+ \exp_not:N \fill
+ [ black ] ( 0 , 0 ) circle [ radius = \fp_eval:n { \l__liftarm_hole_radius_fp * 2 / 3 } ] ;
+ }
+ { \seq_item:Nn \l__liftarm_trace_item_seq { 3 } }
+ \exp_not:n { \end { scope } \end { scope } }
+ }
+ \tl_if_empty:eTF { \seq_item:Nn \l__liftarm_trace_item_seq { 2 } }
+ {
+ \tl_build_gput_right:ce { g__liftarm_animate_timeline_0_tl }
+ { \theg__liftarm_animate_frame_number_counter x 0 , }
+ }
+ {
+ \pgfmathparse { \use:e { \seq_item:Nn \l__liftarm_trace_item_seq { 2 } } }
+ \tl_build_gput_right:ce { g__liftarm_animate_timeline_\theg__liftarm_animate_step_number_counter _tl }
+ { \theg__liftarm_animate_frame_number_counter x \fp_eval:n { \pgfmathresult } , }
+ }
+ }
+ }
+ \end { scope }
+ \end { scope }
+ }
+ }
+
+\cs_new_protected:Npn \__liftarm_LU_decomposition:
+ {
+ \int_step_inline:nn { \l__liftarm_LU_N_int }
+ {
+ \int_zero_new:c { l__liftarm_LU_P_##1_int }
+ \int_set:cn { l__liftarm_LU_P_##1_int } {##1}
+ }
+ \int_step_inline:nn { \l__liftarm_LU_N_int }
+ {
+ \fp_zero:N \l__liftarm_LU_maxA_fp
+ \int_set:Nn \l__liftarm_LU_imax_int {##1}
+ \int_step_inline:nnn {##1} { \l__liftarm_LU_N_int }
+ {
+ \fp_set:Nn \l__liftarm_LU_tmp_fp { abs ( \cs:w l__liftarm_LU_A_####1_##1_fp\cs_end: ) }
+ \fp_compare:nNnT { \l__liftarm_LU_tmp_fp } > { \l__liftarm_LU_maxA_fp }
+ {
+ \fp_set_eq:NN \l__liftarm_LU_maxA_fp \l__liftarm_LU_tmp_fp
+ \int_set:Nn \l__liftarm_LU_imax_int {####1}
+ }
+ }
+ \int_compare:nNnF { \l__liftarm_LU_imax_int } = {##1}
+ {
+ \int_set_eq:Nc \l__liftarm_LU_j_int { l__liftarm_LU_P_##1_int }
+ \int_set_eq:cc { l__liftarm_LU_P_##1_int } { l__liftarm_LU_P_\int_use:N \l__liftarm_LU_imax_int _int }
+ \int_set_eq:cN { l__liftarm_LU_P_\int_use:N \l__liftarm_LU_imax_int _int } \l__liftarm_LU_j_int
+ \int_step_inline:nn { \l__liftarm_LU_N_int }
+ {
+ \fp_set_eq:Nc \l__liftarm_LU_tmp_fp { l__liftarm_LU_A_##1_####1_fp }
+ \fp_set_eq:cc { l__liftarm_LU_A_##1_####1_fp } { l__liftarm_LU_A_\int_use:N \l__liftarm_LU_imax_int _####1_fp }
+ \fp_set_eq:cN { l__liftarm_LU_A_\int_use:N \l__liftarm_LU_imax_int _####1_fp } \l__liftarm_LU_tmp_fp
+ }
+ }
+ \int_step_inline:nnn { ##1 + 1 } { \l__liftarm_LU_N_int }
+ {
+ \fp_set:cn { l__liftarm_LU_A_####1_##1_fp }
+ { \cs:w l__liftarm_LU_A_####1_##1_fp\cs_end: / \cs:w l__liftarm_LU_A_##1_##1_fp\cs_end: }
+ \int_step_inline:nnn { ##1 + 1 } { \l__liftarm_LU_N_int }
+ {
+ \fp_sub:cn { l__liftarm_LU_A_####1_########1_fp }
+ { \cs:w l__liftarm_LU_A_####1_##1_fp\cs_end: * \cs:w l__liftarm_LU_A_##1_########1_fp\cs_end: }
+ }
+ }
+ }
+ }
+
+\cs_new_protected:Npn \__liftarm_LU_solve:
+ {
+ \int_step_inline:nn { \l__liftarm_LU_N_int }
+ {
+ \fp_zero_new:c { l__liftarm_LU_x_##1_fp }
+ \fp_set_eq:cc { l__liftarm_LU_x_##1_fp } { l__liftarm_LU_b_\int_use:c { l__liftarm_LU_P_##1_int }_fp }
+ \int_step_inline:nn { ##1 - 1 }
+ {
+ \fp_sub:cn { l__liftarm_LU_x_##1_fp }
+ { \cs:w l__liftarm_LU_A_##1_####1_fp\cs_end: * \cs:w l__liftarm_LU_x_####1_fp\cs_end: }
+ }
+ }
+ \int_step_inline:nnnn { \l__liftarm_LU_N_int } { -1 } { 1 }
+ {
+ \int_step_inline:nnn { ##1 + 1 } { \l__liftarm_LU_N_int }
+ {
+ \fp_sub:cn { l__liftarm_LU_x_##1_fp }
+ { \cs:w l__liftarm_LU_A_##1_####1_fp\cs_end: * \cs:w l__liftarm_LU_x_####1_fp\cs_end: }
+ }
+ \fp_set:cn { l__liftarm_LU_x_##1_fp } { \cs:w l__liftarm_LU_x_##1_fp\cs_end: / \cs:w l__liftarm_LU_A_##1_##1_fp\cs_end: }
+ }
+ }
+
+\cs_new:Npn \__liftarm_Mod:nn #1#2
+ {
+ min
+ (
+ Mod
+ (
+ \fp_eval:n { \cs:w l__liftarm_connect_two_#1_option_#2_angle_fp\cs_end: - \cs:w l__liftarm_connect_angle_#1_fp\cs_end: } ,
+ 360
+ ) ,
+ Mod
+ (
+ \fp_eval:n { \cs:w l__liftarm_connect_angle_#1_fp\cs_end: - \cs:w l__liftarm_connect_two_#1_option_#2_angle_fp\cs_end: } ,
+ 360
+ )
+ )
+ }
+
+%%> \subsection{Document commands and environment}
+
+\NewDocumentCommand \liftarm { O {} m m m }
+ { \__liftarm_default:nnnn {#1} {#2} {#3} {#4} }
+
+\NewDocumentCommand \liftarmanimate { O {} m m m }
+ {
+ \bool_set_true:N \l__liftarm_animate_bool
+ \stepcounter { g__liftarm_animate_number_of_animation_counter }
+ \setcounter { g__liftarm_animate_number_of_steps_counter } { -1 }
+ \tl_build_gbegin:N \g__liftarm_animate_frames_tl
+ \tl_build_gbegin:N \g__liftarm_animate_frames_trace_tl
+ \setcounter { g__liftarm_animate_step_number_counter } { -1 }
+ \foreach \l__liftarm_animate_value_tl in {#3}
+ {
+ \stepcounter { g__liftarm_animate_number_of_steps_counter }
+ \tl_build_gput_right:Ne \g__liftarm_animate_frames_tl
+ {
+ \exp_not:n { \newframe \stepcounter { g__liftarm_animate_step_number_counter } #4 }
+ { \l__liftarm_animate_value_tl }
+ }
+ }
+ \tl_build_gend:N \g__liftarm_animate_frames_tl
+ \int_step_inline:nnn { 0 } { \theg__liftarm_animate_number_of_steps_counter }
+ {
+ \tl_clear_new:c { g__liftarm_animate_timeline_##1_tl }
+ \tl_build_gbegin:c { g__liftarm_animate_timeline_##1_tl }
+ }
+ \tl_build_gput_right:cn { g__liftarm_animate_timeline_0_tl } { c , }
+ \setcounter { g__liftarm_animate_frame_number_counter } { \theg__liftarm_animate_number_of_steps_counter }
+ \file_if_exist:nF { \c_sys_jobname_str \theg__liftarm_animate_number_of_animation_counter . tln }
+ {
+ \iow_open:Nn \g__liftarm_animate_write_timeline_iow
+ { \c_sys_jobname_str \theg__liftarm_animate_number_of_animation_counter . tln }
+ \iow_now:Ne \g__liftarm_animate_write_timeline_iow { \c_colon_str \c_colon_str c , 0 }
+ \iow_close:N \g__liftarm_animate_write_timeline_iow
+ }
+ \begin { animateinline } [ #1 , timeline = \c_sys_jobname_str \theg__liftarm_animate_number_of_animation_counter . tln ] {#2}
+ \tl_tail:N \g__liftarm_animate_frames_tl%remove the first \newframe
+ \tl_build_gend:N \g__liftarm_animate_frames_trace_tl
+ \g__liftarm_animate_frames_trace_tl
+ \end { animateinline }
+ \iow_open:Nn \g__liftarm_animate_write_timeline_iow { \c_sys_jobname_str \theg__liftarm_animate_number_of_animation_counter . tln }
+ \int_step_inline:nnn { 0 } { \theg__liftarm_animate_number_of_steps_counter }
+ {
+ \tl_build_gend:c { g__liftarm_animate_timeline_##1_tl }
+ \iow_now:Ne \g__liftarm_animate_write_timeline_iow
+ { \c_colon_str \c_colon_str \cs:w g__liftarm_animate_timeline_##1_tl\cs_end: ##1 }
+ }
+ \iow_close:N \g__liftarm_animate_write_timeline_iow
+ \bool_set_false:N \l__liftarm_animate_bool
+ }
+
+\NewDocumentCommand \liftarmconstruct { m }
+ {
+ \tl_gput_right:Nn \g__liftarm_construct_tl {#1}
+ \g__liftarm_construct_tl
+ }
+
+\NewDocumentCommand \liftarmconstructclear {}
+ { \tl_gclear:N \g__liftarm_construct_tl }
+
+\NewDocumentEnvironment { liftarmconnect } { O {} +b }
+ {
+ \pgfkeys { / liftarm , #1 }
+ %verify that the contents consists only of commands \liftarm because the contents of this environment are processed several times
+ \DeclareExpandableDocumentCommand \liftarm { O {} m m m } {}%expandable for usage in \tl_set:Ne
+ \tl_set:Ne \l__liftarm_tmp_tl {#2}
+ \tl_remove_all:Nn \l__liftarm_tmp_tl { \par }
+ \tl_if_blank:VF \l__liftarm_tmp_tl
+ { \PackageError { liftarm } { The~environment~liftarmconnect~should~only~consist~of~commands~\protect \liftarm } {} }
+ \int_zero:N \l__liftarm_LU_N_int
+ \RenewDocumentCommand \liftarm { O {} m m m } { \int_incr:N \l__liftarm_LU_N_int }
+ #2
+ \fp_set:Nn \l__liftarm_connect_det_fp { \pgf@yy * \pgf@xx - \pgf@yx * \pgf@xy }
+ \int_case:nnF { \l__liftarm_LU_N_int }
+ {
+ { 0 }
+ {}
+ { 1 }
+ {
+ \RenewDocumentCommand \liftarm { O {} m m m }
+ { \__liftarm_default:nnnn {##1} {##2} {##3} {##4} }
+ }
+ { 2 }
+ {
+ \int_zero:N \l__liftarm_connect_count_int
+ \int_zero:N \l__liftarm_connect_equation_int
+ \seq_clear:N \l__liftarm_connect_coordinate_seq
+ \fp_set_eq:NN \l__liftarm_origin_connect_initial_fp \l__liftarm_origin_fp
+ \RenewDocumentCommand \liftarm { O {} m m m }
+ {
+ \int_incr:N \l__liftarm_connect_count_int
+ \fp_zero_new:c { l__liftarm_connect_angle_\int_use:N \l__liftarm_connect_count_int _fp }
+ \pgfmathparse {##4}
+ \fp_set:cn { l__liftarm_connect_angle_\int_use:N \l__liftarm_connect_count_int _fp } { \pgfmathresult }
+ \fp_set_eq:NN \l__liftarm_origin_fp \l__liftarm_origin_connect_initial_fp
+ \pgfkeys
+ {
+ / liftarm / connect_algorithm ,
+ coordinate = \pgfkeysvalueof { / liftarm / coordinate } ,
+ ##1
+ }
+ \__liftarm_def_coord:n {##2}
+ \fp_set_eq:cN { l__liftarm_connect_two_\int_to_Alph:n { \l__liftarm_connect_count_int }_x_fp } \g__liftarm_coord_x_fp
+ \fp_set_eq:cN { l__liftarm_connect_two_\int_to_Alph:n { \l__liftarm_connect_count_int }_y_fp } \g__liftarm_coord_y_fp
+ \int_compare:nNnTF { \l__liftarm_connect_count_int } = { 1 }
+ {
+ \clist_map_inline:en { \pgfkeysvalueof { / liftarm / connect_algorithm / coordinate } }
+ {
+ \seq_set_split:Nnn \l__liftarm_coordinate_seq { / } {####1}
+ \tl_clear_new:c { l__liftarm_connect_two_A_length_coord_\seq_item:Nn \l__liftarm_coordinate_seq { 2 }_tl }
+ \tl_set:ce { l__liftarm_connect_two_A_length_coord_\seq_item:Nn \l__liftarm_coordinate_seq { 2 }_tl }
+ { \seq_item:Nn \l__liftarm_coordinate_seq { 1 } - \fp_use:N \l__liftarm_origin_fp }
+ \seq_put_right:Ne \l__liftarm_connect_coordinate_seq { \seq_item:Nn \l__liftarm_coordinate_seq { 2 } }
+ }
+ }
+ {
+ \clist_map_inline:en { \pgfkeysvalueof { / liftarm / connect_algorithm / coordinate } }
+ {
+ \seq_set_split:Nnn \l__liftarm_coordinate_seq { / } {####1}
+ \seq_if_in:NeT \l__liftarm_connect_coordinate_seq { \seq_item:Nn \l__liftarm_coordinate_seq { 2 } }
+ {
+ \int_incr:N \l__liftarm_connect_equation_int
+ \int_compare:nNnT { \l__liftarm_connect_equation_int } > { 1 }
+ { \PackageError { liftarm } { There~are~too~many~conditions~for~2~liftarms } {} }
+ \pgfmathparse
+ { \cs:w l__liftarm_connect_two_A_length_coord_\seq_item:Nn \l__liftarm_coordinate_seq { 2 }_tl\cs_end: }
+ \fp_set:Nn \l__liftarm_connect_two_A_length_fp { \pgfmathresult }
+ \pgfmathparse { \seq_item:Nn \l__liftarm_coordinate_seq { 1 } }
+ \fp_set:Nn \l__liftarm_connect_two_B_length_fp { \pgfmathresult - \l__liftarm_origin_fp }
+ }
+ }
+ }
+ }
+ #2
+ \fp_set:Nn \l__liftarm_connect_two_length_fp
+ {
+ sqrt (
+ ( \l__liftarm_connect_two_A_x_fp - \l__liftarm_connect_two_B_x_fp ) ^ 2
+ + ( \l__liftarm_connect_two_A_y_fp - \l__liftarm_connect_two_B_y_fp ) ^ 2
+ )
+ }
+ \fp_set:Nn \l__liftarm_connect_two_angle_fp
+ {
+ atand (
+ \l__liftarm_connect_two_B_y_fp - \l__liftarm_connect_two_A_y_fp ,
+ \l__liftarm_connect_two_B_x_fp - \l__liftarm_connect_two_A_x_fp
+ )
+ }
+ \fp_set:Nn \l__liftarm_connect_two_A_angle_fp
+ {
+ acosd (
+ (
+ ( \l__liftarm_connect_two_A_length_fp ) ^ 2 + ( \l__liftarm_connect_two_length_fp ) ^ 2
+ - ( \l__liftarm_connect_two_B_length_fp ) ^ 2
+ ) / ( 2 * \l__liftarm_connect_two_A_length_fp * \l__liftarm_connect_two_length_fp )
+ )
+ }
+ \fp_set:Nn \l__liftarm_connect_two_B_angle_fp
+ {
+ acosd (
+ (
+ ( \l__liftarm_connect_two_B_length_fp ) ^ 2 + ( \l__liftarm_connect_two_length_fp ) ^ 2
+ - ( \l__liftarm_connect_two_A_length_fp ) ^ 2
+ ) / ( 2 * \l__liftarm_connect_two_B_length_fp * \l__liftarm_connect_two_length_fp )
+ )
+ }
+ \fp_set:cn { l__liftarm_connect_two_1_option_0_angle_fp }
+ { \l__liftarm_connect_two_angle_fp + \l__liftarm_connect_two_A_angle_fp }
+ \fp_set:cn { l__liftarm_connect_two_1_option_1_angle_fp }
+ { \l__liftarm_connect_two_angle_fp - \l__liftarm_connect_two_A_angle_fp }
+ \fp_set:cn { l__liftarm_connect_two_2_option_0_angle_fp }
+ { 180 + \l__liftarm_connect_two_angle_fp - \l__liftarm_connect_two_B_angle_fp }
+ \fp_set:cn { l__liftarm_connect_two_2_option_1_angle_fp }
+ { 180 + \l__liftarm_connect_two_angle_fp + \l__liftarm_connect_two_B_angle_fp }
+ \pgfmathparse
+ {
+ \__liftarm_Mod:nn { 1 } { 0 } + \__liftarm_Mod:nn { 2 } { 0 }
+ >
+ \__liftarm_Mod:nn { 1 } { 1 } + \__liftarm_Mod:nn { 2 } { 1 }
+ }
+ \tl_set:Ne \l__liftarm_tmp_tl { \pgfmathresult }
+ \int_zero:N \l__liftarm_connect_count_int
+ \RenewDocumentCommand \liftarm { O {} m m m }
+ {
+ \int_incr:N \l__liftarm_connect_count_int
+ \__liftarm_default:nnnn {##1} {##2} {##3}
+ { \fp_use:c { l__liftarm_connect_two_\int_use:N \l__liftarm_connect_count_int _option_\l__liftarm_tmp_tl _angle_fp } }
+ }
+ }
+ }
+ {
+ \int_zero:N \l__liftarm_connect_count_int
+ \int_zero:N \l__liftarm_connect_equation_int
+ \seq_clear:N \l__liftarm_connect_coordinate_seq
+ \fp_set_eq:NN \l__liftarm_origin_connect_initial_fp \l__liftarm_origin_fp
+ \RenewDocumentCommand \liftarm { O {} m m m } { \__liftarm_connect:nnnn {##1} {##2} {##3} {##4} }
+ #2
+ \int_compare:nNnF { \l__liftarm_connect_equation_int } = { \l__liftarm_LU_N_int }
+ {
+ \PackageError { liftarm }
+ {
+ The~Jacobian~matrix~is~not~square~
+ (the~size~is~\int_use:N \l__liftarm_connect_equation_int \space by~\int_use:N \l__liftarm_LU_N_int )
+ } {}
+ }
+ \int_zero:N \l__liftarm_LU_count_int
+ \int_step_inline:nn { \l__liftarm_LU_N_int }
+ { \fp_zero_new:c { l__liftarm_LU_b_##1_fp } }
+ \__liftarm_connect_stop_criterion:
+ \bool_while_do:Nn \l__liftarm_LU_bool
+ {
+ \int_step_inline:nn { \l__liftarm_LU_N_int }
+ {
+ \int_step_inline:nn { \l__liftarm_LU_N_int }
+ { \fp_set:cn { l__liftarm_LU_A_##1_####1_fp } { \cs:w l__liftarm_connect_Jacobian_##1_####1_tl\cs_end: } }
+ }
+ \__liftarm_LU_decomposition:
+ \__liftarm_LU_solve:
+ \int_step_inline:nn { \l__liftarm_LU_N_int }
+ { \fp_sub:cn { l__liftarm_connect_angle_##1_fp } { \cs:w l__liftarm_LU_x_##1_fp\cs_end: } }
+ \int_incr:N \l__liftarm_LU_count_int
+ \__liftarm_connect_stop_criterion:
+ }
+ \int_zero:N \l__liftarm_connect_count_int
+ \RenewDocumentCommand \liftarm { O {} m m m }
+ {
+ \int_incr:N \l__liftarm_connect_count_int
+ \__liftarm_default:nnnn {##1} {##2} {##3}
+ { \fp_eval:n { \cs:w l__liftarm_connect_angle_\int_use:N \l__liftarm_connect_count_int _fp\cs_end: / deg } }
+ }
+ }
+ #2
+ }
+ {}
-\gappto\liftarm@constructfigure{#3}
-\expandafter\liftarm@construction\expandafter[\liftarm@constructoptions]{#1}
-}
-\newenvironment{liftarmconstruction}[1][]{\def\liftarm@constructoptions{#1}\def\liftarm@constructfigure{}\begin{enumerate}}{\end{enumerate}}
-\newcounter{liftarm@animatenumberofsteps}
-\newcounter{liftarm@animateframenumber}
-\newcounter{liftarm@animatestepnumber}
-\newwrite\liftarm@animatewritetimeline
-\newcounter{liftarm@animatenumberofanimation}
-\newcommand{\liftarmanimate}[4][]{%
-\liftarm@animatetrue%
-\addtocounter{liftarm@animatenumberofanimation}{1}%
-\setcounter{liftarm@animatenumberofsteps}{-1}%
-\gdef\liftarm@animateframes{}%
-\gdef\liftarm@animateframestrace{}%
-\setcounter{liftarm@animatestepnumber}{-1}%
-\foreach\liftarm@n in {#3}{%
-\addtocounter{liftarm@animatenumberofsteps}{1}%
-\gappto\liftarm@animateframes{\newframe\addtocounter{liftarm@animatestepnumber}{1}#4}%
-\xappto\liftarm@animateframes{{\liftarm@n}}%
-}%
-\patchcmd{\liftarm@animateframes}{\newframe}{}{}{}%
-\csgdef{liftarm@animatetimeline0}{c,}%
-\foreach\liftarm@n in {1,...,\theliftarm@animatenumberofsteps}{%
-\csgdef{liftarm@animatetimeline\liftarm@n}{}%
-}%
-\setcounter{liftarm@animateframenumber}{\theliftarm@animatenumberofsteps}%
-\IfFileExists{\jobname\theliftarm@animatenumberofanimation.tln}{}{%
-\immediate\openout\liftarm@animatewritetimeline=\jobname\theliftarm@animatenumberofanimation.tln%
-\immediate\write\liftarm@animatewritetimeline{::c,0}%
-\immediate\closeout\liftarm@animatewritetimeline%
-}%
-\begin{animateinline}[#1,timeline=\jobname\theliftarm@animatenumberofanimation.tln]{#2}%
-\liftarm@animateframes%
-\liftarm@animateframestrace%
-\end{animateinline}%
-\immediate\openout\liftarm@animatewritetimeline=\jobname\theliftarm@animatenumberofanimation.tln%
-\foreach\liftarm@n in {0,...,\theliftarm@animatenumberofsteps}{%
-\immediate\write\liftarm@animatewritetimeline{::\csname liftarm@animatetimeline\liftarm@n\endcsname\liftarm@n}%
-}%
-\immediate\closeout\liftarm@animatewritetimeline%
-\liftarm@animatefalse%
-}
\endinput \ No newline at end of file