diff --git a/CMakeLists.txt b/CMakeLists.txt index 38d945ae..0eaee653 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,13 +39,13 @@ message( STATUS "Build type: ${CMAKE_BUILD_TYPE}" ) option( CPM_DISABLE "Don't use CPM to retrieve dependencies" "$ENV{CPM_DISABLE}" ) option( OEMSH_PORTABILITY_TWEAKS "Enable some portability tweaks" OFF ) +list( APPEND CMAKE_MODULE_PATH + "${CMAKE_SOURCE_DIR}/cmake" + ) + if( NOT CPM_DISABLE ) message( STATUS "Downloading dependencies with CPM" ) - list( APPEND CMAKE_MODULE_PATH - "${CMAKE_SOURCE_DIR}/cmake" - ) - include( CPM ) CPMAddPackage( @@ -126,12 +126,20 @@ else() message( STATUS "Not found D2: Some parts of doc disabled" ) endif() +find_program( PDF2SVG NAMES pdf2svg ) +if( PDF2SVG ) + message( STATUS "Found pdf2svg: ${PDF2SVG}" ) +else() + message( STATUS "Not found pdf2svg: Some parts of doc disabled" ) +endif() + if( CMakeUtils_FOUND ) set( CMAKE_UTILS * ) set( COVERAGE_GLOBAL_ONLY ON ) include( CMakeUtils ) endif() +include( ConfigureFileBuildTime ) include( GNUInstallDirs ) set( CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS diff --git a/cmake/ConfigureFileBuildTime.cmake b/cmake/ConfigureFileBuildTime.cmake new file mode 100644 index 00000000..b9690639 --- /dev/null +++ b/cmake/ConfigureFileBuildTime.cmake @@ -0,0 +1,33 @@ + +################################################################################ +function( configure_file_build_time INPUT OUTPUT ) + set( OPTIONS ) + set( ONEVALUEARGS ) + set( MULTIVALUEARGS VARS ) +# set( MULTIVALUEARGS ARGS VARS ) + cmake_parse_arguments( CFBT + "${OPTIONS}" + "${ONEVALUEARGS}" + "${MULTIVALUEARGS}" + ${ARGN} + ) + + while( CFBT_VARS ) + list( POP_FRONT CFBT_VARS VAR VAL ) + list( APPEND VARS "-D${VAR}=\"${VAL}\"" ) + endwhile() + + file( WRITE + "${OUTPUT}.cmake" + "configure_file(\"${INPUT}\" \"${OUTPUT}\" ${CFBT_UNPARSED_ARGUMENTS})" +# "configure_file(\"${INPUT}\" \"${OUTPUT}\" ${CFBT_ARGS})" + ) + + add_custom_command( + OUTPUT ${OUTPUT} + DEPENDS ${INPUT} + COMMAND ${CMAKE_COMMAND} + ${VARS} + -P "${OUTPUT}.cmake" + ) +endfunction() diff --git a/default.nix b/default.nix index 0b47584e..98348f33 100644 --- a/default.nix +++ b/default.nix @@ -4,11 +4,14 @@ , cmake-utils , git , texlive +, pdf2svg , cli11 , indicators , pugixml , qtbase , wrapQtAppsHook +, fetchzip +, runCommand , withPortabilityTweaks ? false }: @@ -40,8 +43,45 @@ stdenv.mkDerivation { cmake-utils git wrapQtAppsHook + pdf2svg (texlive.combine { - inherit (texlive) scheme-small standalone pgfplots; + inherit (texlive) scheme-small standalone pgfplots unicode-math; + # https://ctan.org/tex-archive/fonts/lete-sans-math + # TODO use buildTeXLivePackage +# lete-sans-math = pkgs.texlivePackages.buildTeXLivePackage { +## revision = 64540; +# shortdesc = "Lato-based OpenType Math font for LuaTeX and XeTeX"; +## stripPrefix = 0; +## fontMaps = [ +## "Map andika.map" +## ]; +## sha512.run = "4da9904459345033aa87deeb0019c8c4a39fbafcd59d973717ed2c4a410ece528944c69669b6a5ecf6ef8bb790f60bba909468e001485c405e7cf8775b7533e5"; +## sha512.doc = "50684857dc25ad942aff18eedec04c9e27e4e408f748c208f8527c5096e600d26769ec6f82e2f02e72ab472dfb662f12bb009156293a12daa2dc0676d63ed446"; +# hasRunfiles = false; +# license = [ "lppl13c" ]; +# version = "0.41"; +# }; + lete-sans-math = { + pkgs = [ + (runCommand "lete-sans-math" rec { + src = fetchzip { + url = "https://github.com/abccsss/LeteSansMath/archive/refs/tags/v${passthru.version}.zip"; + hash = "sha256-q+WwdSUeHIffpgrJ6GKzyQz+iNxUTeHr4GQZsT0r1Kw="; + }; + passthru = { + pname = "lete-sans-math"; + version = "0.50"; + tlType = "run"; + }; + } '' + mkdir -p \ + $out/tex/latex/lete-sans-math/ \ + $out/fonts/opentype/public/lete-sans-math/ + cp $src/*.sty $src/*.ltx $out/tex/latex/lete-sans-math/ + cp $src/*.otf $out/fonts/opentype/public/lete-sans-math/ + '') + ]; + }; }) ]; diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 749062d8..07b47b42 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,5 +1,38 @@ add_custom_target( doc ) +if( CMakeUtils_Latex_FOUND AND PDF2SVG ) + compile_latex_file( "interval" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/interval.svg" + SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/latex" + TEXINPUTS "${CMAKE_CURRENT_SOURCE_DIR}/latex" + REGISTER_TO "INTERVAL_FILES" + SHELL_ESCAPE + ) +endif() + +configure_file_build_time( + "${CMAKE_CURRENT_SOURCE_DIR}/interval.md.in" + "${CMAKE_CURRENT_BINARY_DIR}/interval.md" + @ONLY + VARS + INTERVAL_SVG "./latex/interval.svg" + ) + +add_custom_target( interval + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/interval.md" ${INTERVAL_FILES} + ) + +add_dependencies( doc interval ) + +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/interval.md" + ${INTERVAL_FILES} + DESTINATION "${CMAKE_INSTALL_DOCDIR}" + CONFIGURATIONS Release + OPTIONAL + ) + configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/openemsh.1.in" "${CMAKE_CURRENT_BINARY_DIR}/openemsh.1" diff --git a/doc/interval.md.in b/doc/interval.md.in new file mode 100644 index 00000000..ef59e577 --- /dev/null +++ b/doc/interval.md.in @@ -0,0 +1,42 @@ +# Meshing algorithm + +## Scope + +The meshing process consists of two parts: +- The geometrical analysis that, given a structure, outputs some `MeshlinePolicies` ("Here is something of interest that must be meshed according those rules", typically an `Edge` must be meshed according Thirds rule) and some `Interval` in between. +- The `Meshline` generation, that consist of filling each `Interval` while respecting enclosing `MeshlinePolicies`' specific rules. + +Despite being actually just the last step of the whole process, this explanatory document is about the generation of `Meshlines` at `Interval` level. + +## Reference + + + +- `x`: Position of `MeshlinePolicies`. +- `m`: Position of the middle of the `Interval` between two `MeshlinePolicies`. +- `h`: Half of the Interval between two `MeshlinePolicies`. +- `f`: Smoothness factor `[1;2]`. +- `d`: Distance between the two lines around a `MeshlinePolicy`. +- `dinit`: Space between `x` and the first line (may not be the half of `d`). +- `dmax`: Maximal authorized space between two lines. +- `s`: Space to fill of lines. +- `z`: Distance from the first line (belonging to `MeshlinePolicy`) to the last line before `m` (the middle of the `Interval`). +- `lz`: Number of lines before the middle of the `Interval` (minus the line belonging to the `MeshlinePolicy`). + +Orange lines belong to `MeshlinePolicies`, green lines belong to `Interval`. + +## Algorithm + +### Rules + +- Axes are meshed `Interval` by `Interval`, smallest first. +- `Intervals` are meshed **half by half**. +- Spaces between lines, including `d` are always bounded to `dmax`. +- Space between lines cannot exceed adjacent spaces multiplied by the smoothness factor. + +### Steps + +- Choose `dmax` among `Interval`'s `dmax` and projection from both sides' `d` of `f**(lz+1)`, so the sizes of the two cells around `m` (belonging to both sides) will respect the smoothness factor (`f`). +- Reduce `d` until enough lines are in the half (`lz >= lmin`). +- Reduce the smoothness factor (which augments the spaces between lines, except `d`) until `z` matches `s`, that is to say until the last line of the half overlaps with `m` (actually just passed `m`). +- Trim out the last line, that overlaps `m` (a line at `m`, that will count for both halves, will be placed instead). diff --git a/doc/latex/interval.tex b/doc/latex/interval.tex new file mode 100644 index 00000000..9193da3b --- /dev/null +++ b/doc/latex/interval.tex @@ -0,0 +1,239 @@ +\documentclass[ + tikz, + multi=false, + convert=pdf2svg + ]{standalone} + +%\usepackage{etoolbox} +\usepackage{fontspec} +\setmainfont[Ligatures=TeX, Mapping=tex-text]{Lato} +%\usepackage[default]{lato} +\usepackage{unicode-math} +%\setmathfont{Lete Sans Math} +\setmathfont{LeteSansMath.otf} +%\usepackage{lete-sans-math} +\usepackage{tikz} +\usetikzlibrary{math} +\usepackage{xfp} + +\begin{document} +\begin{tikzpicture} + +\def\width{10} +\def\height{5} +\def\ox{\fpeval{\width /2}} +\def\oy{\fpeval{\height /2}} +\coordinate (O) at (\ox,\oy); + +\tiny +\path [use as bounding box] (0,0) rectangle (\width,\height); + +% SHAPE +%\filldraw [line width=0.5pt, fill=orange] (\ox,\oy) +% +(-0.5,-0.5) node[draw, fill=black, circle, inner sep=1pt] {} node[below left] {0} -- +% +(0.5,-0.5) node[draw, fill=black, circle, inner sep=1pt] {} node[below right] {1} -- +% +(0.5,0.5) node[draw, fill=black, circle, inner sep=1pt] {} node[above right] {2} -- +% +(-0.5,0.5) node[draw, fill=black, circle, inner sep=1pt] {} node[above left] {3} -- +% cycle; + +% PORTS +%\draw [line width=2pt] (\ox,\oy) ++(-0.5,0) node[right] {1} +(0,-0.5) -- +(0,0.5); +%\draw [line width=2pt] (\ox,\oy) ++(0,-0.5) node[above] {2} +(-0.5,0) -- +(0.5,0); + + + +% MID LINE +\draw [line width=0.5pt, dotted] (O) +(0,-2) node[below] {$m$} -- +(0,1); + +% EDGE LINES +\draw [line width=0.5pt, dotted] (\ox,\oy) +(-4,-2) node[below] {$x$} -- +(-4,1); +\draw [line width=0.5pt, dotted] (\ox,\oy) +(4,-2) node[below] {$x$} -- +(4,1); + +% POLICY LINES +%\draw [line width=0.5pt, orange] (\ox,\oy) ++(-4,0) +% +(-0.2,-1) -- +(-0.2,1) +% +(0.2,-1) -- +(0.2,1); +%\draw [line width=0.5pt, orange] (\ox,\oy) ++(4,0) +% +(-0.1,-1) -- +(-0.1,1) +% +(0.2,-1) -- +(0.2,1); +% Function: policy line +% #1 : x +% #2 : x1 (relative to x) +% #3 : x2 (relative to x) +\newcommand{\policylines}[3]{% + \draw [line width=0.5pt, orange] (\ox,\oy) ++(#1,0) + +(#2,-1) -- +(#2,1) + +(#3,-1) -- +(#3,1)% +} +\policylines{-4}{-0.3}{0.3}; % 1/2 - Halfs rule +\policylines{4}{-0.1}{0.2}; % 1/3 - Thirds rule + +% LINES +%\newcommand{\drawline}[2][violet]{% +% \draw [line width=0.5pt, color={#1}] (\ox,\oy) +% +(#2,-1) -- +(#2,1)% +%} +%\drawline[orange]{3}; +%\newcommand{\drawline}[2][violet]{% +% \draw [line width=0.5pt, {#1}] (\ox,\oy) +\newcommand{\drawline}[2][line width=0.5pt, color=black]{% + \draw [{#1}] (\ox,\oy) + +(#2,-1) -- +(#2,1)% +} +%\drawline[orange, dotted]{3}; +%\drawline{2.5}; +% +%\draw [line width=0.5pt, violet] (\ox,\oy) ++(-3.7,-1) +%% ++(0,0) +(0,2) +% ++(1.2,0) -- +(0,2) +% ++(2.4,0) -- +(0,2) +%; + + +% First, produce a list of lines coordinates +% Then, use the list to draw the lines and draw annotations +% https://tex.stackexchange.com/questions/662928/is-this-the-right-way-to-understand-let-def-edef-gdef-xdef-newcommand-ren +% edef daclare a var, performing expansion +% xdef declare a global edef var +\xdef\lines{} +% TODO define as func with args { x, d_init, d, direction } +\foreach \n in {1,...,2} { + \edef\tmp{\lines,\n} + \xdef\lines{\tmp} +} + +%%%% #1 : output var +%%%% #2 : n +%%%% #3 : x +%%%% #4 : d +%%%% #5 : d_init +%%%% #6 : smoothness +%%%% #7 : direction +%%%\newcommand{\createlines}[6] {% +%%% % ##1 : n +%%% \newcommand{\calculate}[1] {% +%%%% \fpeval{#3 + ##1}% +%%% \fpeval{(#3 + #5) + (#4 * (#6 ^ ##1))}% +%%% } +%%% % ##1 : s +%%% % ##2 : d +%%% %% ##3 : n +%%% \newcommand{\calculates}[2] {% +%%%% \fpeval{#3 + ##1}% +%%% \fpeval{##1 + (##2 * #6)}% +%%% } +%%% \edef\currents{\fpeval{#3 + #5}} +%%% \edef\currentd{#4} +%%% \expandafter\xdef\csname #1\endcsname{} +%%% +%%% \foreach \n in {1,...,#2} {% +%%% \edef\currentd{\fpeval{\currentd * #6}} +%%% \edef\currents{\fpeval{\currents + \currentd}} +%%% \ifnum \n = 1% +%%%% \edef\tooutput{\calculate{\n}}% +%%% \edef\tooutput{\currents}% +%%%% \edef\tooutput{\calculates{\currents}{\currentd}}% +%%% \else% +%%%% \edef\tooutput{\csname #1\endcsname,\calculate{\n}}% +%%% \edef\tooutput{\csname #1\endcsname,\currents}% +%%%% \edef\tooutput{\csname #1\endcsname,\calculate{\n}}% +%%% \fi% +%%% \expandafter\xdef\csname #1\endcsname{\tooutput}% +%%% }% +%%%} + +% #1 : output var +% #2 : n +% #3 : x +% #4 : d +% #5 : d_init +% #6 : smoothness +% #7 : direction (+ | -) +\newcommand{\createlines}[7] {% + \tikzmath{ + real \d, \s; + \d = #4; + \s = #3 #7 #5; + let \ret =; + for \i in {1,...,#2} { + \d = \d * #6; + \s = \s #7 \d; + if \i == 1 + then { \ret = \s; } + else { \ret = "\ret,\s"; }; + }; + } + \expandafter\xdef\csname #1\endcsname{\ret} +} + +%\createlines{linus}{3}{-4} +%\createlines{linus}{3}{-4}{0.6}{0.3}{2} +\createlines{lines}{7}{-4}{0.6}{0.3}{1.1}{+} + +\edef\orig{\fpeval{-4+0.3}} + +\foreach \n [expand list=true, count=\i] in {\lines} { + \drawline[green]{\n}; +% \draw [line width=0.5pt, red] (\ox,\oy) +% ++(\n,-1) -- +(0,2) node[above] {\n}; + +% \draw [line width=0.5pt] (\ox,\oy) ++(-4,0) ++(0.3,0) + \draw [line width=0.5pt] (\ox,\oy) ++(\orig,0) + ++(0,1) -- +(0,0.5); + \ifnum \i = 4 + \draw [line width=0.5pt] (\ox,\oy) + ++(\n,1) -- +(0,0.5); + \draw [line width=0.5pt] (\ox,\oy) ++(0,1.5) + +(\orig,0) + .. controls +(0,0.3) and +(0,0.3) .. + +(\n,0) + +(\fpeval{(\orig+\n)/2},0.2) node[above] {$z$} + +(\fpeval{(\orig+\n)/2},0.4) node[above] {$lz=\i$}; + \fi +} + +\edef\dmax{1} + +\foreach \n [ + expand list=true, + count=\i, + remember=\n as \lastn (initially \fpeval{-4+0.3}) +] in {\lines} { + \draw [line width=0.5pt] (\ox,\oy) ++(0,1) + +(\lastn,0) .. controls +(0,0.2) and +(0,0.2) .. +(\n,0) + +(\fpeval{(\lastn+\n)/2},0.2) node[above] {$d\cdot f$$^\i$}; + + \pgfmathparse{\dmax < \fpeval{abs(\lastn-\n)}} + \ifnum \pgfmathresult>0 + \draw [line width=0.5pt] (\ox,\oy) ++(0,1) + ++(\lastn,0) .. controls +(0,-0.2) and +(0,-0.2) .. +(\dmax,0) + +(\fpeval{(\dmax)/2},-0.2) node[below] {$d_{max}$}; + \fi +} + + + +% ANNOTATIONS +\draw [line width=0.5pt] (\ox,\oy) ++(-4,1) + +(-0.3,0) .. controls +(0,0.2) and +(0,0.2) .. +(0.3,0) + +(0,0.2) node[above] {$d$}; + +\draw [line width=0.5pt] (\ox,\oy) ++(-4,-1) + +(0,0) .. controls +(0,-0.1) and +(0,-0.1) .. +(0.3,0) + +(0.25,-0.1) node[below] {$d_{init}$}; + +\draw [line width=0.5pt] (\ox,\oy) ++(0,-1) + +(-3.7,0) .. controls +(0,-0.2) and +(0,-0.2) .. +(0,0) + +(-2,-0.2) node[below] {$s$}; + +%\draw [line width=0.5pt, yellow] (\ox,\oy) ++(0,-1) +% +(-3.7,0) to [bend right=30] +(0,0) +% +(-2,-0.2) node[below] {s}; + +\draw [line width=0.5pt] (\ox,\oy) ++(0,-1.5) + +(-4,0) .. controls +(0,-0.2) and +(0,-0.2) .. +(0,0) + +(-2,-0.2) node[below] {$h$}; + + +\end{tikzpicture} +\end{document}