Ei teneste av

Den sentrale filosofien til Æxis (anglifisert som Aexis) er ekteskapet mellom logikk og kunst. Estetikk på ein akse. Få ting fangar denne foreininga betre enn Bézier-kurver. Dei er kurver ein kan skreddarsy til eitkvart formål, som ein kan lime saman med kvarandre for å lage kva som helst form. Dei held fast ved dei strenge matematiske definisjonane sine, men likevel bøyer dei seg til teiknaren sin kreative vilje.

Ein annan viktig del av grafisk design er vektorbasert grafikk. Mange bilete bør vere skalerbare og zoombare. Nokre bilete, meir enn andre. Under er eit porteføljeprosjekt av Æxis, som syner krafta i å bruke LaTeX for å matematisk generere ein fraktal som ei .svg-fil, noko som tillèt ein "uendeleg" zoom.

I staden for å lage Fibonacci-spiralen på den enkle måten, ved å setje saman kvartsirklar, brukte vi heller kubiske Bézier-kurver som ei tilnærming, noko som tillét oss vise fram ende- og styrepunkta deira. Kunst krev eit brot med perfeksjon. Den endelege zoomen når 2 699x. Dette er for ein Fibonacci-mosaikk på tjueein iterasjonar. Fleire iterasjonar var ikkje mogleg på grunn av grensa på maksstorleik i TeX. Under kan du sjå LaTeX-koden som vart brukt for å rekursivt generere diagrammet.

fibonacci_tiling.tex

\documentclass[margin=2mm]{standalone}
\usepackage{tikz}
\usepackage{xparse}
\usepackage{xcolor}
\usepackage{graphicx}
\usepackage{adjustbox}
\usepackage{amssymb}

% Fargar sette til merkevarepaletten
\definecolor{fibwhite}{HTML}{FFFFFF}
\definecolor{baseblue}{HTML}{6C63FF} 
\definecolor{fiblightgray}{HTML}{F2F2F2}
\definecolor{fibgray}{HTML}{D6D6E3}

% Eg brukte ein lysare blå for å gjere dei stipla linjene meir synlege
\colorlet{fibblue}{baseblue!60!white}

\ExplSyntaxOn

% Konstant for den beste Bezier-tilnærminga av ein kvartsirkel
\fp_new:N \c__fibtile_k_fp
\fp_set:Nn \c__fibtile_k_fp { 0.27614 }

% Skriftsskaleringskonstant og -variabel for å halde god storleik på Bezier-notasjonen relativt til flisa han er på
\fp_new:N \c_fibtile_ink_base_fp
\fp_set:Nn \c_fibtile_ink_base_fp { 0.00665 } 
\fp_new:N \l_fibtile_local_scale_fp

% Variablar for rotasjon og fargelegging
\int_new:N \l_fibtile_rotation_int
\tl_new:N \l_fibtile_current_color_tl

% #1, #2, #3 og #4 svarer til x- og y-koordinatane til 
% start- og endepunkta til Bezier-kurva, respektivt. 
% #5 svarer til den reverse indeksen
\cs_new:Nn \fibtile_draw_bezier_curve:nnnnn 
 { 
  \fp_set:Nn \l_tmpa_fp { (#3) - (#1) } 
  \fp_set:Nn \l_tmpb_fp { (#4) - (#2) } 

  % Definerer x- og y-koordinatane til styrepunkta
  \fp_set:Nn \l_tmpc_fp { #1 + \c__fibtile_k_fp * (\l_tmpa_fp - (-1) * \l_tmpb_fp) }
  \fp_set:Nn \l_tmpd_fp { #2 + \c__fibtile_k_fp * ((-1) * \l_tmpa_fp + \l_tmpb_fp) }
  \fp_set:Nn \l_tmpe_fp { #3 + \c__fibtile_k_fp * (-\l_tmpa_fp - (-1) * \l_tmpb_fp) }
  \fp_set:Nn \l_tmpf_fp { #4 + \c__fibtile_k_fp * ((-1) * \l_tmpa_fp - \l_tmpb_fp) }

  % Teikning av sjølve Bezier-kurva
  \draw [black, line~width=0.8 * \fp_use:N \l_fibtile_local_scale_fp pt] 
   (#1, #2) .. controls (\fp_use:N \l_tmpc_fp, \fp_use:N \l_tmpd_fp) 
   ~and~ (\fp_use:N \l_tmpe_fp, \fp_use:N \l_tmpf_fp) .. (#3, #4);

  % Teikning av styringslinjene
  \draw [black!55, line~width= 1.2 * \fp_use:N \l_fibtile_local_scale_fp pt, dash~pattern=on~ 8 * \fp_use:N \l_fibtile_local_scale_fp pt~off~ 4 * \fp_use:N \l_fibtile_local_scale_fp pt] 
   (#1, #2) -- (\fp_use:N \l_tmpc_fp, \fp_use:N \l_tmpd_fp) -- (\fp_use:N \l_tmpe_fp, \fp_use:N \l_tmpf_fp) -- (#3, #4);
  
  % Lagring av endepunkta
  \coordinate~ (P_#5_0-3)~ at~ (#3,~ #4);

  % Lagring av styrepunkta
  \coordinate~ (P_#5_1)~ at~ (\fp_use:N \l_tmpe_fp,~ \fp_use:N \l_tmpf_fp);
  \coordinate~ (P_#5_2)~ at~ (\fp_use:N \l_tmpc_fp,~ \fp_use:N \l_tmpd_fp);
 }

% Laging av variablane nødvendige for loopen som genererer Fibonacci-sekvensen
\int_new:N \l_fibtile_vara_int
\int_new:N \l_fibtile_varb_int
\int_new:N \l_fibtile_vartemp_int

\seq_new:N \l_fibtile_numbers_seq

% Eg brukte den glidande-vindauge-algoritmen fordi rekursjon er veldig tregt i TeX
\cs_new:Nn \fibtile_generate_seq:n
 {
  \int_set:Nn \l_fibtile_vara_int { 1 } 
  \int_set:Nn \l_fibtile_varb_int { 1 } 
  \seq_clear:N \l_fibtile_numbers_seq
  \int_step_inline:nn { #1 } 
   { 
    \seq_put_right:NV \l_fibtile_numbers_seq \l_fibtile_vara_int
    \int_set_eq:NN \l_fibtile_vartemp_int \l_fibtile_varb_int
    \int_set:Nn \l_fibtile_varb_int { \l_fibtile_vara_int + \l_fibtile_varb_int }
    \int_set_eq:NN \l_fibtile_vara_int \l_fibtile_vartemp_int
   }
 }

% Laging av variablane nødvendige for å halde styr på hjørna i Fibonacci-mosaikken
\int_new:N \l_fibtile_xmin_int
\int_new:N \l_fibtile_xmax_int
\int_new:N \l_fibtile_ymin_int
\int_new:N \l_fibtile_ymax_int

\cs_new:Nn \fibtile_draw_tiling:n
 {
  \fibtile_generate_seq:n { #1 }

  \seq_map_indexed_inline:Nn \l_fibtile_numbers_seq
   {
    % Teksten er skalert relativt til iterasjonen, men koeffisienten lengst til høgre er der for å ta høgde for
    %  skaleringa av lerretet som skjer basert på det totale talet på iterasjonar
    % (sjå adjustboxen i \NewDocumentCommand på slutten)
    \fp_set:Nn \l_fibtile_local_scale_fp { ##2 * \c_fibtile_ink_base_fp * 1.618034^(12 - #1) }
    
    % Eg mappar fargar til (n - i) mod 4-verdien for iterasjonen, slik at han går i syklus gjennom fargane 
    % langs den reverse indeksen, noko som gjev dei største kvadrata ein konsekvent utsjånad for alle innputt-verdiar
    \tl_set:Nn \l_fibtile_current_color_tl
     {
      \int_case:nn { \int_mod:nn { #1 - ##1 } { 4 } }
       {
        { 0 } { fibgray   }
        { 1 } { fibblue   }
        { 2 } { fiblightgray }
        { 3 } { fibwhite   }
       }
     }

    \int_case:nn { \int_mod:nn { ##1 } { 4 } }
     {
      { 1 } 
       { 
        % Det inste kvadratet er teke hand om separat, då det er frøet
        \int_compare:nTF { ##1 == 1 }
         { 
          \draw[black, fill=\l_fibtile_current_color_tl, line~width=\fp_eval:n{0.4 * \l_fibtile_local_scale_fp}pt] 
           (0,0) rectangle (##2, ##2);

          % Eg teiknar den første kurva frå topp-venstre til nedre-høgre for å samstemme med rotasjonen mot klokka som flislegginga følgjer
          \fibtile_draw_bezier_curve:nnnnn { 0 } { ##2 } { ##2 } { 0 } 
           { \int_eval:n { #1 - ##1 } } 

          \int_set:Nn \l_fibtile_xmax_int { ##2 }
          \int_set:Nn \l_fibtile_ymax_int { ##2 }

          % Lagrar det inste endepunktet
          \coordinate~ (P_#1_0-3)~ at~ (0, \l_fibtile_ymax_int);
         }
         { 
          \draw[black, fill=\l_fibtile_current_color_tl, line~width=\fp_eval:n{0.4 * \l_fibtile_local_scale_fp}pt] 
           (\l_fibtile_xmin_int, \l_fibtile_ymin_int - ##2) rectangle (\l_fibtile_xmax_int, \l_fibtile_ymin_int);

          \int_set:Nn \l_fibtile_ymin_int { \l_fibtile_ymin_int - ##2 }
          
          \fibtile_draw_bezier_curve:nnnnn { \l_fibtile_xmin_int } { \l_fibtile_ymin_int + ##2 } { \l_fibtile_xmax_int } { \l_fibtile_ymin_int } 
           { \int_eval:n { #1 - ##1 } }
         }
       }
      { 2 } 
       { 
        \draw[black, fill=\l_fibtile_current_color_tl, line~width=\fp_eval:n{0.4 * \l_fibtile_local_scale_fp}pt] 
         (\l_fibtile_xmax_int, \l_fibtile_ymin_int) rectangle (\l_fibtile_xmax_int + ##2, \l_fibtile_ymax_int);

        \int_set:Nn \l_fibtile_xmax_int { \l_fibtile_xmax_int + ##2 }

        \fibtile_draw_bezier_curve:nnnnn { \l_fibtile_xmax_int - ##2 } { \l_fibtile_ymin_int } { \l_fibtile_xmax_int } { \l_fibtile_ymax_int } 
         { \int_eval:n { #1 - ##1 } } 
       }
      { 3 } 
       { 
        \draw[black, fill=\l_fibtile_current_color_tl, line~width=\fp_eval:n{0.4 * \l_fibtile_local_scale_fp}pt] 
         (\l_fibtile_xmin_int, \l_fibtile_ymax_int) rectangle (\l_fibtile_xmax_int, \l_fibtile_ymax_int + ##2);

        \int_set:Nn \l_fibtile_ymax_int { \l_fibtile_ymax_int + ##2 }

        \fibtile_draw_bezier_curve:nnnnn { \l_fibtile_xmax_int } { \l_fibtile_ymax_int - ##2 } { \l_fibtile_xmax_int - ##2 } { \l_fibtile_ymax_int } 
         { \int_eval:n { #1 - ##1 } } 
       }
      { 0 } 
       { 
        \draw[black, fill=\l_fibtile_current_color_tl, line~width=\fp_eval:n{0.4 * \l_fibtile_local_scale_fp}pt] 
         (\l_fibtile_xmin_int - ##2, \l_fibtile_ymin_int) rectangle (\l_fibtile_xmin_int, \l_fibtile_ymax_int);

        \int_set:Nn \l_fibtile_xmin_int { \l_fibtile_xmin_int - ##2 }
        
        \fibtile_draw_bezier_curve:nnnnn { \l_fibtile_xmin_int + ##2 } { \l_fibtile_ymax_int } { \l_fibtile_xmin_int } { \l_fibtile_ymin_int }  
         { \int_eval:n { #1 - ##1 } } 
       }
     }
    % Eg puttar min føretrekte versjon av Binet sin formel i det siste, største kvadratet 
    \int_compare:nT { ##1 == #1 }
     {
      % Utrekning av posisjonsvariablane basert på mod 4-verdien til den siste iterasjonen
      \int_case:nn { \int_mod:nn { ##1 } { 4 } }
       {
        { 1 } 
         { 
          \fp_set:Nn \l_tmpa_fp { \l_fibtile_xmin_int + ##2 * 0.7284 }
          \fp_set:Nn \l_tmpb_fp { \l_fibtile_ymin_int + ##2 * 0.5320 } 
         }
        { 2 } 
         { 
          \fp_set:Nn \l_tmpa_fp { \l_fibtile_xmax_int - ##2 * 0.5320 }
          \fp_set:Nn \l_tmpb_fp { \l_fibtile_ymin_int + ##2 * 0.7284 } 
         }
        { 3 } 
         { 
          \fp_set:Nn \l_tmpa_fp { \l_fibtile_xmax_int - ##2 * 0.7284 }
          \fp_set:Nn \l_tmpb_fp { \l_fibtile_ymax_int - ##2 * 0.5320 } 
         }
        { 0 } 
         { 
          \fp_set:Nn \l_tmpa_fp { \l_fibtile_xmin_int + ##2 * 0.5320 }
          \fp_set:Nn \l_tmpb_fp { \l_fibtile_ymax_int - ##2 * 0.7284 } 
         }
       }

      \node[
       scale = \fp_eval:n { \l_fibtile_local_scale_fp * 1.3 },
       transform~shape, 
       rotate = - \l_fibtile_rotation_int
      ] at ( \fp_use:N \l_tmpa_fp, \fp_use:N \l_tmpb_fp ) 
       { $ F\sb {n} = \frac{\varphi^n - (-\varphi)^{-n}}{\sqrt{5}} $ };
     }
   }
 }

% Ved kvar iterasjon gror mosaikken i ei retning 90 grader rotert frå retninga han grodde langs sist. 
% Ved iterasjonsverdiar delelege med fire, så puttar mosaikken det største kvadratet til venstre, noko som ser best ut.
% Derfor mot-roterer eg heile mosaikken basert på i mod 4-verdien.
\cs_new:Nn \fibtile_rotate_tiling:n 
 {
  \int_set:Nn \l_fibtile_rotation_int { \int_mod:nn { #1 } { 4 } * -90 }
  
  \begin{scope}[rotate = \l_fibtile_rotation_int]
   \fibtile_draw_tiling:n { #1 }
  \end{scope}
 }

\cs_new:Nn \fibtile_draw_points:n 
 {
  \fibtile_generate_seq:n { #1 }

  \seq_map_indexed_inline:Nn \l_fibtile_numbers_seq 
   {
    \fp_set:Nn \l_fibtile_local_scale_fp { ##2 * \c_fibtile_ink_base_fp * 1.618034^(12 - #1) }
    
    % tmpa svarer til label-posisjonen til endepunkta og det første styrepunktet
    % (bortsett frå det inste endepunktet)
    \tl_set:Ne \l_tmpa_tl 
     {
      \int_case:nn { \int_mod:nn { \int_eval:n { #1 - ##1 } } { 4 } }
       {
        { 0 } { left }
        { 1 } { above }
        { 2 } { right }
        { 3 } { below }
       }
     }
    
    % tmpb svarer til label-posisjonen til det andre styringspunktet
    \tl_set:Nn \l_tmpb_tl 
     {
      \int_case:nn { \int_mod:nn { \int_eval:n { #1 - ##1 } } { 4 } }
       {
        { 0 } { above }
        { 1 } { right }
        { 2 } { below }
        { 3 } { left }
       }
     } 

    % Det inste endepunktet
    \int_compare:nT { ##1 == 1 } 
     {
      \fill[black] 
       (P_\int_eval:n { #1 } _0-3)~ circle~ (\fp_eval:n{2 * \l_fibtile_local_scale_fp}pt)
       node[
        scale = \fp_use:N \l_fibtile_local_scale_fp, 
        \l_tmpb_tl 
       ] {$P \sb {3, \int_eval:n { #1 }}$};
     }

    % Resten av endepunkta;
    % Alle av dei, bortsett frå P_0,0, syner ein likskap mellom det siste endepunktet til ein iterasjon og det første endepunktet til ein annan.
    \int_compare:nTF { ##1 == #1 } 
     {
      \fill[black] 
       (P_\int_eval:n { #1 - ##1 }_0-3)~ circle~ (\fp_eval:n{2 * \l_fibtile_local_scale_fp}pt)
       node[
        scale = \fp_use:N \l_fibtile_local_scale_fp, 
        \l_tmpa_tl 
       ] {$P \sb {0, \int_eval:n { #1 - ##1 }}$};
     }
     { 
      % Eg endrar rekkefølgja på likskapen når labelen er under, for å få det til å lesast i rett retning.
      \tl_if_eq:NnTF \l_tmpa_tl { below } 
       {
        \fill[black] 
         (P_\int_eval:n { #1 - ##1 }_0-3)~ circle~ (\fp_eval:n{2 * \l_fibtile_local_scale_fp}pt)
         node[
          scale = \fp_use:N \l_fibtile_local_scale_fp, 
          \l_tmpa_tl 
         ] {$ P \sb {0, \int_eval:n { #1 - ##1 + 1 }} = P \sb {3, \int_eval:n { #1 - ##1 }}$};
       }
       {
        \fill[black] 
         (P_\int_eval:n { #1 - ##1 }_0-3)~ circle~ (\fp_eval:n{2 * \l_fibtile_local_scale_fp}pt)
         node[
          scale = \fp_use:N \l_fibtile_local_scale_fp, 
          \l_tmpa_tl 
         ] {$P \sb {3, \int_eval:n { #1 - ##1 }} = P \sb {0, \int_eval:n { #1 - ##1 + 1 }}$};
       }
     }

    % Styringspunkt
    \draw[fill=white, line~width= 0.4 * \fp_use:N \l_fibtile_local_scale_fp pt] 
     (P_\int_eval:n { #1 - ##1 }_1)~ circle~ (\fp_eval:n{2 * \l_fibtile_local_scale_fp}pt)
     node[
      scale = \fp_use:N \l_fibtile_local_scale_fp, 
      \l_tmpa_tl 
     ] {$P \sb {1, \int_eval:n { #1 - ##1 }}$};

    \draw[fill=white, line~width= 0.4 * \fp_use:N \l_fibtile_local_scale_fp pt] 
     (P_\int_eval:n { #1 - ##1 }_2)~ circle~ (\fp_eval:n{2 * \l_fibtile_local_scale_fp}pt)
     node[
      scale = \fp_use:N \l_fibtile_local_scale_fp, 
      \l_tmpb_tl 
     ] {$P \sb {2, \int_eval:n { #1 - ##1 }}$};
   }
 }

\NewDocumentCommand{\FibonacciTiling}{ O{1} m }
 { 
  % Når eg teikna med punkt som eining, fann eg ut at #2 = 12 såg best ut.
  % Sidan sidelengda til kvadratet for kvar iterasjon er større/mindre med ein faktor omtrent lik det gylne snittet
  % Er punkta skalerte som dette 
  \begin{adjustbox}{scale=#1}
   \begin{tikzpicture}[
     x = \fp_eval:n { 1.618034^(12 - #2) } pt, 
     y = \fp_eval:n { 1.618034^(12 - #2) } pt
    ]

    \fibtile_rotate_tiling:n { #2 }
    
    \fibtile_draw_points:n { #2 }

   \end{tikzpicture}
  \end{adjustbox}
 }

\ExplSyntaxOff

\begin{document}

\FibonacciTiling[2]{21}

\end{document}
    

Æxis har òg laga alle logoane til Kvåle Solutions, og har både sytt for at dei er skarpe .svg-filer, og at dei passar inn i Kvåle Solutions-merkevaren.

TeXtract Logo Føx Logo Æxis Logo Annex2 Logo

Om ditt oppdrag krev meir enn berre grafisk design, som typesetting, webutvikling eller ymse språktenester, så kan du halde alt innanfor Kvåle Solutions. Dei ulike tenestene våre vil saumlaust samarbeide for å løyse alle aspekt av oppdraget ditt, medan du held deg til eitt fast kontaktpunkt (SPOC)