En tjeneste av

Den sentrale filosofien til Æxis (anglifisert som Aexis) er giftemålet mellom logikk og kunst. Estetikk på en akse. Få ting fanger denne foreningen bedre enn Bézier-kurver. De er kurver man kan skreddersy til ethvert formål, som man kan lime sammen med hverandre for å lage hvilken som helst form. De holder fast ved sine strenge matematiske definisjoner, men likevel bøyer de seg til tegnerens kreative vilje.

En annen viktig del av grafisk design er vektor-basert grafikk. Mange bilder bør være skalerbare og zoombare – noen bilder, mer enn andre. Under er et porteføljeprosjekt av Æxis, som viser kraften av å bruke LaTeX for å matematisk generere en fraktal som en .svg fil, noe som tillater en "uendelig" zoom.

I stedet for å lage Fibonacci-spiralen på den enkle måten, ved å sette sammen kvartsirkler, brukte vi heller kubiske Bézier-kurver som en tilnærming, noe som lot oss vise fram ende- og styrepunktene deres. Kunst krever et brudd med perfeksjon. Den endelige zoomen når 2 699x. Dette er for en Fibonacci-mosaikk på tjueen iterasjoner. Flere iterasjoner var ikke mulig på grunn av grensen for maksstørrelse i TeX. Under kan du se LaTeX koden som ble brukt for å rekursivt generere diagrammet.

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

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

% Jeg brukte en lysere blå for å gjøre de stiplede linjene mer synlige.
\colorlet{fibblue}{baseblue!60!white}

\ExplSyntaxOn

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

% Skriftsskaleringskonstant og -variabel for å holde god størrelse på Bezier-notasjonen relativ til flisen den 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

% Variabler 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-koordinatene av 
% start- og endepunktene til  Bezier-kurven, 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) } 

    % Defining the x- and y-coordinates of the control points
    \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) }

    % Tegning av selve Bezier-kurven
    \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);

    % Tegning 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 endepunktene
    \coordinate~ (P_#5_0-3)~ at~ (#3,~ #4);

    % Lagring av styrepunktene
    \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 variablene nødvendig for loopen som generer 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

% Jeg brukte den glidende-vindu-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 variablene nødvendig for å holde styr på Fibonacci-mosaikkens hjørner
\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øyre er der for å ta høyde for
        %  skaleringen av lerretet som skjer basert på det totale antallet iterasjoner
        % (se adjustboxen i \NewDocumentCommand på slutten)
        \fp_set:Nn \l_fibtile_local_scale_fp { ##2 * \c_fibtile_ink_base_fp * 1.618034^(12 - #1) }
        
        % Jeg mapper farger til (n - i) mod 4 verdien for iterasjonen, slik at den går i syklus gjennom fargene 
        % langs den reverse indeksen, noe som gir de største kvadratene et konsekvent utseende for alle innputt-verdier
        \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 } 
              { 
                % Den innerste kvadraten er tatt hånd om seperat, da 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);

                    % Jeg tegner den første kurven fra topp-venste til nedre-høyre for å samstemme med rotasjoen mot klokken som flisleggingen følger
                    \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 }

                    % Lagrer det innereste 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 } } 
              }
          }
         % Jeg putter min foretrukne versjon av Binets formel i den siste, største kvadraten 
        \int_compare:nT { ##1 == #1 }
          {
            % Kalkulering av posisjonsvariablene 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 hver iterasjon så gror mosaikken i en retning 90 grader rotert fra retningen den grodde langs sist. 
% Ved iterasjonsverdien delbare med fire, så putter mosaikken den største kvadraten til venstre, som ser best ut.
% Derfor mot-roterer jeg hele 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 endepunktene og det første styrepunktet
        % (bortsett fra det innerste 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 innerste 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 endepunktene;
        % Alle av dem, bortsett i fra P_0,0, viser fra, en likhet mellom det siste endepunktet av en iterasjon og det første endepunktet av en annen.
        \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 }}$};
          }
          { 
            % Jeg endrer rekkefølgen på likheten når labelen er under, for å få det til å lese 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 jeg tegnet med punkt som enhet, fant jeg at #2 = 12 så best ut.
    % Siden sidelengden av kvadraten for hver iterasjon er større/mindre med en faktor omtrent lik det gylne snitt
    % Er punktene skalert 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 også lagd alle logoene til Kvåle Solutions, og både sørget for at de var skarpe .svg-filer, og at de passet inn i Kvåle Solutions-merkevaren.

TeXtract Logo Føx Logo Æxis Logo Annex2 Logo

Hvis ditt oppdrag krever mer enn bare grafisk design, som typesetting, webutvikling eller ymse språktjenester, så kan du holde alt innenfor Kvåle Solutions. Våre forskjellige tjenester vil sømløst samarbeide for å løse alle aspekter av oppdraget ditt, mens du kun forholder deg til ett fast kontaktpunkt (SPOC)